botframework - 自定义适配器收到错误:[onTurnError] unhandled error: TypeError: bot.reply is not a function
问题描述
我们创建了一个自定义 Botbuilder 适配器来连接到名为botbuilder-adapter-vonage-js的 Vonage API 。为了测试适配器的基本功能,使用基本的机器人回复,我们向 Vonage 号码发送了一条短信,应该会收到一条短信回复“Hello Back”,但会收到以下错误:
[onTurnError] unhandled error: TypeError: bot.reply is not a function
不确定如何实际调试自定义适配器以找到它被破坏的位置。
很高兴找到熟悉Botkit Core 库和Botkit Platform Adapters的人来帮助解决这个问题。我在下面附上了 Express Server (webhook-server.js)。
// webhook-server.js
require('dotenv').config();
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
const SendMessagesAPI = require('./Vonage-SEND-messages-api');
const VonageAdapter = require('botbuilder-adapter-vonage-js');
const Botkit = require('botkit');
const {
BotFrameworkAdapter,
InspectionMiddleware,
MemoryStorage,
InspectionState,
UserState,
ConversationState,
} = require('botbuilder');
const { MicrosoftAppCredentials } = require('botframework-connector');
// This bot's main dialog.
const { IntersectionBot } = require('./bot');
const { Message } = require('@vonage/server-sdk');
const creds = {
apiKey: process.env.VONAGE_API_KEY,
apiSecret: process.env.VONAGE_API_SECRET,
applicationId: process.env.VONAGE_APPLICATION_ID,
privateKey: process.env.VONAGE_APPLICATION_PRIVATE_KEY_PATH,
};
const config = {
to_number: process.env.TO_NUMBER,
from_number: process.env.FROM_NUMBER,
// enable_incomplete: true
};
// Create Adapter
const adapter = new VonageAdapter(creds, config);
// Create the Storage provider and the various types of BotState.
const memoryStorage = new MemoryStorage();
const inspectionState = new InspectionState(memoryStorage);
const userState = new UserState(memoryStorage);
const conversationState = new ConversationState(memoryStorage);
// Create and add the InspectionMiddleware to the adapter.
adapter.use(
new InspectionMiddleware(
inspectionState,
userState,
conversationState,
new MicrosoftAppCredentials(
process.env.MicrosoftAppId,
process.env.MicrosoftAppPassword
)
)
);
app.post('/webhooks/dlr', (req, res) => {
res.status(200).end();
});
// Catch-all for errors.
adapter.onTurnError = async (, error) => {
// This check writes out errors to console log .vs. app insights.
// NOTE: In production environment, you should consider logging this to Azure
// application insights. See https://aka.ms/bottelemetry for telemetry
// configuration instructions.
console.error(`\n [onTurnError] unhandled error: ${error}`);
// Send a trace activity, which will be displayed in Bot Framework Emulator
await .sendTraceActivity(
'OnTurnError Trace',
`${error}`,
'https://www.botframework.com/schemas/error',
'TurnError'
);
// Send a message to the user
await .sendActivity('The bot encountered an error or bug.');
await .sendActivity(
'To continue to run this bot, please fix the bot source code.'
);
// Clear out state
await conversationState.clear();
};
// Create the main dialog.
const bot = new IntersectionBot(conversationState, userState);
// Listen for incoming requests.
app.post('/webhooks/inbound', (req, res) => {
console.log('/webhooks/inbound req.body', req.body);
adapter.processActivity(req, res, async () => {
console.log(context);
// [onTurnError] unhandled error: TypeError: Cannot read property 'from' of undefined
// await bot.run();
// [onTurnError] unhandled error: TypeError: .reply is not a function
// await .reply('I heard a message!');
// [onTurnError] unhandled error: TypeError: bot.reply is not a function
await bot.reply('Hello Back!');
});
res.status(200).end();
});
app.post('/webhooks/status', (req, res) => {
res.status(200).end();
});
app.listen(port, () => {
console.log(` Server running at http://localhost:${port}`);
});
回复
Server running at http://localhost:3000
/webhooks/inbound req.body {
message_uuid: 'e93a3007-f7a5-436a-8ba7-c46d64343d80',
to: { type: 'sms', number: '12018994297' },
from: { type: 'sms', number: '15754947000' },
timestamp: '2021-08-27T21:14:51.228Z',
usage: { price: '0.0057', currency: 'EUR' },
message: {
content: { type: 'text', text: 'Hello' },
sms: { num_messages: '1' }
},
direction: 'inbound'
}
TurnContext {
_respondedRef: { responded: false },
_turnState: TurnContextStateCollection(2) [Map] {
'httpStatus' => 200,
Symbol(state) => { state: [Object], hash: '{}' }
},
_onSendActivities: [],
_onUpdateActivity: [],
_onDeleteActivity: [],
_turn: 'turn',
_locale: 'locale',
bufferedReplyActivities: [],
_adapter: VonageAdapter {
middleware: MiddlewareSet { middleware: [Array] },
BotIdentityKey: Symbol(BotIdentity),
OAuthScopeKey: Symbol(OAuthScope),
name: 'Vonage Adapter',
middlewares: null,
botkit_worker: [class VonageBotWorker extends BotWorker],
credentials: {
apiKey: '4f2ff535',
apiSecret: 'jtYzPbh3MXr8M1Hr',
applicationId: '978500cf-7ea8-4d7b-ac54-2b42f67b28a2',
privateKey: './private.key'
},
options: {},
to_number: '15754947000',
from_number: '12018994297',
enable_incomplete: undefined,
turnError: [AsyncFunction (anonymous)]
},
_activity: {
id: 'e93a3007-f7a5-436a-8ba7-c46d64343d80',
timestamp: 2021-08-27T21:14:39.573Z,
channelId: 'vonage-sms',
conversation: { id: '15754947000' },
from: { id: '15754947000' },
recipient: { id: '12018994297' },
text: 'Hello',
channelData: {
message_uuid: 'e93a3007-f7a5-436a-8ba7-c46d64343d80',
to: [Object],
from: [Object],
timestamp: '2021-08-27T21:14:51.228Z',
usage: [Object],
message: [Object],
direction: 'inbound'
},
type: 'message'
}
}
[onTurnError] unhandled error: TypeError: bot.reply is not a function
- 机器人套件版本:
- 消息平台:Vonage
- 节点版本:v14.16.1
- 操作系统:MAC
解决方案
看起来您的自定义适配器是使用 Botkit 和 BotFramework 构建的,类似于其他 Botkit适配器。但是,您的机器人的实现更符合仅为 BotFramework 构建的机器人,但您正在尝试调用reply()
属于 Botkit 机器人的方法。
例如,在 Botkit 的“botbuilder-adapter-twilio-sms”适配器中,您会看到两种使用适配器的方法。首先,在Botkit Basics下,创建了一个适配器,然后由 Botkit 使用以形成控制器。然后,这允许您访问reply()
可从 Botkit 机器人调用的方法。
其次,在BotBuilder Basics下,创建了一个适配器,然后在 Express 服务器的/api/messages
端点中使用该适配器。入站消息被传递到适配器的processActivity()
方法,然后机器人使用该方法进行响应,该sendActivity()
方法可从 BotFramework 适配器的上下文中调用。
我相信缩小您打算使用的实现范围将减轻您收到的错误。
推荐阅读
- react-native - 在 react native 中将状态发送到图像标签的 require 源
- go - 如何计算 Go 中的鼠标点击次数?
- django - Django中如何处理多对多关系?
- json - 如何加载在 HIVE 中压缩的 json snappy
- python - 值错误为“尝试相对导入超出顶级包”
- javascript - javascript过滤一个对象
- node.js - 如何找到具有相同值的所有对象
- python - Python Tornado 响应 GET 请求
- sql - 如何计算一组单词在t-sql中给定数据中出现的次数?
- excel - Excel 公式、文件名、单元格引用、计数、日期