Skip to content

Conversation

compulim
Copy link
Contributor

@compulim compulim commented Nov 9, 2021

Changelog Entry

(No changelog for documentation)

Description

Adding a CHAT_ADAPTER.md to outlines how to use Web Chat outside of Direct Line protocol.

Specific Changes

  • Add CHAT_ADAPTER.md
  • I have added tests and executed them locally
  • I have updated CHANGELOG.md
  • I have updated documentation

Review Checklist

This section is for contributors to review your work.

  • Accessibility reviewed (tab order, content readability, alt text, color contrast)
  • Browser and platform compatibilities reviewed
  • CSS styles reviewed (minimal rules, no z-index)
  • Documents reviewed (docs, samples, live demo)
  • Internationalization reviewed (strings, unit formatting)
  • package.json and package-lock.json reviewed
  • Security reviewed (no data URIs, check for nonce leak)
  • Tests reviewed (coverage, legitimacy)


You can write your own chat adapter to use Web Chat on other services.

Currently, the chat adapter interface Web Chat is using is adopted from the [`BotFramework-DirectLineJS`](https://github.com/microsoft/BotFramework-DirectLineJS) (DLJS) project. This is a "streaming" interface, the chat adapter do not keep any history or state about activities.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Currently, the chat adapter interface Web Chat is using is adopted from the [`BotFramework-DirectLineJS`](https://github.com/microsoft/BotFramework-DirectLineJS) (DLJS) project. This is a "streaming" interface, the chat adapter do not keep any history or state about activities.
Currently, the chat adapter interface Web Chat is using is adopted from the [`BotFramework-DirectLineJS`](https://github.com/microsoft/BotFramework-DirectLineJS) (DLJS) project. This is a "streaming" interface, and the chat adapter does not keep any history or state regarding activities.

Copy link
Contributor

@corinagum corinagum left a comment

Choose a reason for hiding this comment

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

LGTM - small nits. See my last comment (## Readings)


Currently, the chat adapter interface Web Chat is using is adopted from the [`BotFramework-DirectLineJS`](https://github.com/microsoft/BotFramework-DirectLineJS) (DLJS) project. This is a "streaming" interface, the chat adapter do not keep any history or state about activities.

The DLJS interface heavily relies on [Observable](https://github.com/tc39/proposal-observable) and [Bot Framework REST API](https://docs.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference?view=azure-bot-service-4.0#activity-object).
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
The DLJS interface heavily relies on [Observable](https://github.com/tc39/proposal-observable) and [Bot Framework REST API](https://docs.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference?view=azure-bot-service-4.0#activity-object).
The DLJS interface heavily relies on [Observable](https://github.com/tc39/proposal-observable) and the [Bot Framework REST API](https://docs.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference?view=azure-bot-service-4.0#activity-object).


## `activity$: Observable<Activity>`

An Observable to notify Web Chat when an [Activity](https://docs.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference?view=azure-bot-service-4.0#activity-object) arrives. This Observable must contains all recent activities in the conversation, including both incoming and outgoing activities.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
An Observable to notify Web Chat when an [Activity](https://docs.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference?view=azure-bot-service-4.0#activity-object) arrives. This Observable must contains all recent activities in the conversation, including both incoming and outgoing activities.
An Observable is used to notify Web Chat when an [Activity](https://docs.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference?view=azure-bot-service-4.0#activity-object) arrives. This Observable must contains all recent activities in the conversation, including both incoming and outgoing activities.


An Observable to notify Web Chat when an [Activity](https://docs.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference?view=azure-bot-service-4.0#activity-object) arrives. This Observable must contains all recent activities in the conversation, including both incoming and outgoing activities.

When Web Chat post an outgoing activity, this Observable should notify Web Chat with that activity. And the service is expected to "fill-in-the-blank" for the outgoing activity, such as timestamp (the time when the activity is being posted to the service), service-assigned ID, sender ID, conversation ID, etc.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
When Web Chat post an outgoing activity, this Observable should notify Web Chat with that activity. And the service is expected to "fill-in-the-blank" for the outgoing activity, such as timestamp (the time when the activity is being posted to the service), service-assigned ID, sender ID, conversation ID, etc.
When Web Chat posts an outgoing activity, this Observable should notify Web Chat with that activity. And the service is expected to "fill-in-the-blank" for the outgoing activity, such as timestamp (the time when the activity is being posted to the service), service-assigned ID, sender ID, conversation ID, etc.

- `activity.channelData.clientActivityID` is an ID set by Web Chat on all outgoing activity from the current session, ignored if the value is falsy
- `activity.id` is an ID set by the chat platform

If either one of the IDs are the same, Web Chat will consider both are identifying the same activity. And it will replace the activity with last writer win strategy.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
If either one of the IDs are the same, Web Chat will consider both are identifying the same activity. And it will replace the activity with last writer win strategy.
If either one of the IDs are the same, Web Chat will conclude that both are identifying the same activity, and it will replace the activity with 'last writer wins' strategy.


`activity.timestamp` is a service-assigned timestamp and is used to reorder activities in the transcript.

For recent outgoing activities which service-assigned timestamp is not received from the server yet, Web Chat will use a timestamp with an estimated server clock.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
For recent outgoing activities which service-assigned timestamp is not received from the server yet, Web Chat will use a timestamp with an estimated server clock.
For recent outgoing activities for which service-assigned timestamp has not been received from the server yet, Web Chat will use a timestamp with an estimated server clock.


If either one of the signals is not received, Web Chat will not turn the state to "Sent". Web Chat would eventually display a "Send failed, retry" message based on a modifiable timeout value set by the web developer.

Despite "Send failed, retry" message being displayed, the chat service can continue to provide these signals if the activity eventually went through the service. In such case, Web Chat will turn the the activity state from failure to "Sent".
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Despite "Send failed, retry" message being displayed, the chat service can continue to provide these signals if the activity eventually went through the service. In such case, Web Chat will turn the the activity state from failure to "Sent".
Despite "Send failed, retry" message being displayed, the chat service may continue to provide these signals if the activity eventually goes through the service. In such cases, Web Chat will turn the the activity state from failure to "Sent".


Although DLJS is using RxJS for the Observable implementation, it is possible and recommended to use ES Observable with some tweaks. Currently, some chat adapters offered by Web Chat are using Observable implementation from `core-js`, instead of RxJS.

Unlike ES Observable, which is expected to start a new connection on every `subscribe()`, DLJS use a singleton behind the Observable. It means, the first observer subscribed to the `activity$` will start the connection. Subsequent observers subscribing the Observable object will only receive new incoming activity from that point of time. All observers "share" the same connection. We understand this is a drift from the best practices for Observable and will address this in future chat adapter upgrade.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Unlike ES Observable, which is expected to start a new connection on every `subscribe()`, DLJS use a singleton behind the Observable. It means, the first observer subscribed to the `activity$` will start the connection. Subsequent observers subscribing the Observable object will only receive new incoming activity from that point of time. All observers "share" the same connection. We understand this is a drift from the best practices for Observable and will address this in future chat adapter upgrade.
Unlike ES Observable, which is expected to start a new connection on every `subscribe()`, DLJS uses a singleton behind the Observable. This means that the first observer subscribed to the `activity$` will start the connection. Subsequent observers subscribing to the Observable object will only receive new incoming activity from that point of time. All observers "share" the same connection. We understand this is a drift from the best practices for Observable and will address this in future chat adapter upgrade.


Unlike ES Observable, which is expected to start a new connection on every `subscribe()`, DLJS use a singleton behind the Observable. It means, the first observer subscribed to the `activity$` will start the connection. Subsequent observers subscribing the Observable object will only receive new incoming activity from that point of time. All observers "share" the same connection. We understand this is a drift from the best practices for Observable and will address this in future chat adapter upgrade.

There are two Observable exposed by DLJS: `activity$` and `connectionStatus$`. Connection to the chat service should be established only when Web Chat initially subscribe to `activity$`. The chat adapter should have no effect on the connection when Web Chat subscribe to `connectionStatus$`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
There are two Observable exposed by DLJS: `activity$` and `connectionStatus$`. Connection to the chat service should be established only when Web Chat initially subscribe to `activity$`. The chat adapter should have no effect on the connection when Web Chat subscribe to `connectionStatus$`.
There are two Observables exposed by DLJS: `activity$` and `connectionStatus$`. Connection to the chat service should be established only when Web Chat initially subscribes to `activity$`. The chat adapter should have no effect on the connection when Web Chat subscribe to `connectionStatus$`.

- `getSessionId(): Observable<string>` is used to construct a special OAuth sign-in URL with Azure Bot Services
- Please read more about it [here](https://github.com/microsoft/BotFramework-WebChat/blob/main/packages/api/src/hooks/Composer.tsx#L123)
- `referenceGrammarId: string` is for Azure Cognitive Services to improve speech recognition accuracy
- Web Chat pass this value as-is between Azure Bot Services and Azure Cognitive Services
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
- Web Chat pass this value as-is between Azure Bot Services and Azure Cognitive Services
- Web Chat passes this value as-is between Azure Bot Services and Azure Cognitive Services

- `referenceGrammarId: string` is for Azure Cognitive Services to improve speech recognition accuracy
- Web Chat pass this value as-is between Azure Bot Services and Azure Cognitive Services

## Readings
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
## Readings
## Further Reading

How's this?

@compulim compulim marked this pull request as ready for review November 10, 2021 18:44
@compulim compulim added this to the imminent milestone Dec 5, 2023
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