@microsoft/agents-hosting
Version:
Microsoft 365 Agents SDK for JavaScript
133 lines • 5.2 kB
JavaScript
;
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseAdapter = void 0;
const middlewareSet_1 = require("./middlewareSet");
const logger_1 = require("@microsoft/agents-activity/logger");
const logger = (0, logger_1.debug)('agents:base-adapter');
/**
* Abstract base class for all adapters in the Agents framework.
*
* @remarks
* This class provides core functionality for handling conversations, managing middleware,
* authentication, and error handling. Adapters are responsible for translating between
* the Agents framework and specific communication channels (like Teams, Web Chat, etc.).
*
* Key features:
* - Middleware pipeline for processing incoming and outgoing activities
* - Error handling and recovery mechanisms
* - Authentication provider integration
* - Abstract methods for channel-specific operations
* - Context management with revocable proxies for security
*/
class BaseAdapter {
constructor() {
/**
* The middleware set used to process the pipeline of middleware handlers.
*/
this.middleware = new middlewareSet_1.MiddlewareSet();
this.turnError = async (context, error) => {
logger.error(`\n [onTurnError] unhandled error: ${error}`);
// Send a trace activity, which will be displayed in Bot Framework Emulator
await context.sendTraceActivity('OnTurnError Trace', `${error}`, 'https://www.botframework.com/schemas/error', 'TurnError');
// Send a message to the user
await context.sendActivity('The agent encountered an error or bug.');
await context.sendActivity('To continue to run this agent, please fix the source code.');
};
/**
* Symbol key used to store connector client instances in the TurnContext.
*/
this.ConnectorClientKey = Symbol('ConnectorClient');
/**
* Symbol key used to store User Token Client instances in the TurnContext.
*/
this.UserTokenClientKey = Symbol('UserTokenClient');
}
/**
* Gets the error handler for the adapter.
* @returns The current error handler function.
*/
get onTurnError() {
return this.turnError;
}
/**
* Sets the error handler for the adapter.
* @param value - The error handler function to set.
*/
set onTurnError(value) {
this.turnError = value;
}
/**
* Adds middleware to the adapter's middleware pipeline.
* @param middlewares - The middleware to add.
* @returns The adapter instance.
*/
use(...middlewares) {
this.middleware.use(...middlewares);
return this;
}
/**
* This method creates a revocable proxy for the given target object.
* If the environment does not support Proxy.revocable, it returns the original object.
* @remarks
* This is used to enhance security by allowing the proxy to be revoked after use,
* preventing further access to the underlying object.
*
* @param target The target object to be proxied.
* @param handler Optional proxy handler to customize behavior.
* @returns An object containing the proxy and a revoke function.
*/
makeRevocable(target, handler) {
// Ensure proxy supported (some browsers don't)
if (typeof Proxy !== 'undefined' && Proxy.revocable) {
return Proxy.revocable(target, (handler != null) ? handler : {});
}
else {
return {
proxy: target,
revoke: () => {
// noop
}
};
}
}
/**
* Runs the middleware pipeline in sequence.
* @param context - The TurnContext for the current turn.
* @param next - The next function to call in the pipeline.
* @returns A promise representing the completion of the middleware pipeline.
*/
async runMiddleware(context, next) {
if (context && context.activity && context.activity.locale) {
context.locale = context.activity.locale;
}
// Create a revocable proxy for the context which will automatically be revoked upon completion of the turn.
const pContext = this.makeRevocable(context);
try {
await this.middleware.run(pContext.proxy, async () => await next(pContext.proxy));
}
catch (err) {
if (this.onTurnError) {
if (err instanceof Error) {
await this.onTurnError(pContext.proxy, err);
}
else {
throw new Error('Unknown error type: ' + err.message);
}
}
else {
throw err;
}
}
finally {
pContext.revoke();
// Accessing the context after this point, will throw a TypeError.
// e.g.: "TypeError: Cannot perform 'get' on a proxy that has been revoked"
}
}
}
exports.BaseAdapter = BaseAdapter;
//# sourceMappingURL=baseAdapter.js.map