UNPKG

@microsoft/agents-copilotstudio-client

Version:

Microsoft Copilot Studio Client for JavaScript. Copilot Studio Client.

238 lines 10.1 kB
"use strict"; /** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.CopilotStudioWebChat = void 0; const uuid_1 = require("uuid"); const rxjs_1 = require("rxjs"); const logger_1 = require("@microsoft/agents-activity/logger"); const logger = (0, logger_1.debug)('copilot-studio:webchat'); /** * @summary A utility class that provides WebChat integration capabilities for Copilot Studio services. * @remarks * This class acts as a bridge between Microsoft Bot Framework WebChat and Copilot Studio, * enabling seamless communication through a DirectLine-compatible interface. * * ## Key Features: * - DirectLine protocol compatibility for easy WebChat integration * - Real-time bidirectional messaging with Copilot Studio agents * - Automatic conversation management and message sequencing * - Optional typing indicators for enhanced user experience * - Observable-based architecture for reactive programming patterns * * ## Usage Scenarios: * - Embedding Copilot Studio agents in web applications * - Creating custom chat interfaces with WebChat components * - Building conversational AI experiences with Microsoft's bot ecosystem * * @example Basic WebChat Integration * ```typescript * import { CopilotStudioClient } from '@microsoft/agents-copilotstudio-client'; * import { CopilotStudioWebChat } from '@microsoft/agents-copilotstudio-client'; * * // Initialize the Copilot Studio client * const client = new CopilotStudioClient({ * botId: 'your-bot-id', * tenantId: 'your-tenant-id' * }); * * // Create a WebChat-compatible connection * const directLine = CopilotStudioWebChat.createConnection(client, { * showTyping: true * }); * * // Integrate with WebChat * window.WebChat.renderWebChat({ * directLine: directLine, * // ... other WebChat options * }, document.getElementById('webchat')); * ``` * * @example Advanced Usage with Connection Monitoring * ```typescript * const connection = CopilotStudioWebChat.createConnection(client); * * // Monitor connection status * connection.connectionStatus$.subscribe(status => { * switch (status) { * case 0: console.log('Disconnected'); break; * case 1: console.log('Connecting...'); break; * case 2: console.log('Connected and ready'); break; * } * }); * * // Listen for incoming activities * connection.activity$.subscribe(activity => { * console.log('Received activity:', activity); * }); * ``` */ class CopilotStudioWebChat { /** * Creates a DirectLine-compatible connection for integrating Copilot Studio with WebChat. * * This method establishes a real-time communication channel between WebChat and the * Copilot Studio service. The returned connection object implements the DirectLine * protocol, making it fully compatible with Microsoft Bot Framework WebChat components. * * ## Connection Lifecycle: * 1. **Initialization**: Creates observables for connection status and activity streaming * 2. **Conversation Start**: Automatically initiates conversation when first activity is posted * 3. **Message Flow**: Handles bidirectional message exchange with proper sequencing * 4. **Cleanup**: Provides graceful connection termination * * ## Message Processing: * - User messages are validated and sent to Copilot Studio * - Agent responses are received and formatted for WebChat * - All activities include timestamps and sequence IDs for proper ordering * - Optional typing indicators provide visual feedback during processing * * @param client - A configured CopilotStudioClient instance that handles the underlying * communication with the Copilot Studio service. This client should be * properly authenticated and configured with the target bot details. * * @param settings - Optional configuration settings that control the behavior of the * WebChat connection. These settings allow customization of features * like typing indicators and other user experience enhancements. * * @returns A new CopilotStudioWebChatConnection instance that can be passed directly * to WebChat's renderWebChat function as the directLine parameter. The * connection is immediately ready for use and will automatically manage * the conversation lifecycle. * * @throws Error if the provided client is not properly configured or if there are * issues establishing the initial connection to the Copilot Studio service. * * @example * ```typescript * const connection = CopilotStudioWebChat.createConnection(client, { * showTyping: true * }); * * // Use with WebChat * window.WebChat.renderWebChat({ * directLine: connection * }, document.getElementById('webchat')); * ``` */ static createConnection(client, settings) { logger.info('--> Creating connection between Copilot Studio and WebChat ...'); let sequence = 0; let activitySubscriber; let conversation; const connectionStatus$ = new rxjs_1.BehaviorSubject(0); const activity$ = createObservable(async (subscriber) => { activitySubscriber = subscriber; if (connectionStatus$.value < 2) { connectionStatus$.next(2); return; } logger.debug('--> Connection established.'); notifyTyping(); const activity = await client.startConversationAsync(); conversation = activity.conversation; sequence = 0; notifyActivity(activity); }); const notifyActivity = (activity) => { const newActivity = { ...activity, timestamp: new Date().toISOString(), channelData: { ...activity.channelData, 'webchat:sequence-id': sequence++, }, }; logger.debug(`Notify '${newActivity.type}' activity to WebChat:`, newActivity); activitySubscriber === null || activitySubscriber === void 0 ? void 0 : activitySubscriber.next(newActivity); }; const notifyTyping = () => { if (!(settings === null || settings === void 0 ? void 0 : settings.showTyping)) { return; } const from = conversation ? { id: conversation.id, name: conversation.name } : { id: 'agent', name: 'Agent' }; notifyActivity({ type: 'typing', from }); }; return { connectionStatus$, activity$, postActivity(activity) { var _a; logger.info('--> Preparing to send activity to Copilot Studio ...'); if (!((_a = activity.text) === null || _a === void 0 ? void 0 : _a.trim())) { throw new Error('Activity text cannot be empty.'); } if (!activitySubscriber) { throw new Error('Activity subscriber is not initialized.'); } return createObservable(async (subscriber) => { try { const id = (0, uuid_1.v4)(); logger.info('--> Sending activity to Copilot Studio ...'); notifyActivity({ ...activity, id }); notifyTyping(); const activities = await client.askQuestionAsync(activity.text); for (const responseActivity of activities) { notifyActivity(responseActivity); } subscriber.next(id); subscriber.complete(); logger.info('--> Activity received correctly from Copilot Studio.'); } catch (error) { logger.error('Error sending Activity to Copilot Studio:', error); subscriber.error(error); } }); }, end() { logger.info('--> Ending connection between Copilot Studio and WebChat ...'); connectionStatus$.complete(); if (activitySubscriber) { activitySubscriber.complete(); activitySubscriber = undefined; } }, }; } } exports.CopilotStudioWebChat = CopilotStudioWebChat; /** * Creates an RxJS Observable that wraps an asynchronous function execution. * * This utility function provides a clean way to convert async/await patterns * into Observable streams, enabling integration with reactive programming patterns * used throughout the WebChat connection implementation. * * The created Observable handles promise resolution and rejection automatically, * converting them to appropriate next/error signals for subscribers. * * @typeParam T - The type of value that the observable will emit * @param fn - An asynchronous function that receives a Subscriber and performs * the desired async operation. The function should call subscriber.next() * with results and subscriber.complete() when finished. * @returns A new Observable that executes the provided function and emits its results * * @example * ```typescript * const dataObservable = createObservable<string>(async (subscriber) => { * try { * const result = await fetchData(); * subscriber.next(result); * subscriber.complete(); * } catch (error) { * subscriber.error(error); * } * }); * ``` */ function createObservable(fn) { return new rxjs_1.Observable((subscriber) => { Promise.resolve(fn(subscriber)).catch((error) => subscriber.error(error)); }); } //# sourceMappingURL=copilotStudioWebChat.js.map