proactive agent proxy now runs models for responses

This commit is contained in:
Peter Morton 2025-08-07 00:48:43 -05:00
parent 166cded7da
commit 27d7474354
4 changed files with 340 additions and 0 deletions

View File

@ -0,0 +1,9 @@
{
"user": {
"name": "Proactive Agent",
"avatar": "https://storage.googleapis.com/speakeasyai-agent-desktop/img/verint-logo.png",
"userId": "d4de56b5-3fac-4a42-892f-ebec914b6aa3",
"type": "bot"
},
"modelName": "proactiveAgent"
}

View File

@ -0,0 +1,289 @@
console.log({ query: req.query, params: req.params, body: req.body });
const msgrSettings = settings_667ef98d3ee8930a5debcbdb;
const paSettings = proactive_agent_settings;
const studioToken = msgrSettings
? {
Authorization: `Bearer ${msgrSettings.messenger.token}`,
}
: {};
let bot_user = {
...paSettings.user,
};
const app = {
routes: [],
route: function (regexp, fn) {
this.routes.push({ regexp: new RegExp(regexp), function: fn });
},
run: function (req, res) {
const path =
req.params[0].split(
`/ProxyScript/run/${req.params.workspaceId}/${req.params.branch}/${req.params.route}`
)[1] || "/";
for (var route of this.routes) {
console.log(`Checking route: ${route.regexp}`);
console.log(`Against path: ${path}`);
if (route.regexp.test(path)) {
console.log(`Running route: ${route.regexp}`);
console.log(`Path: ${path}`);
console.log(`Function: ${route.function.name}`);
route.function(req, res, route.regexp.exec(path));
return;
}
}
// If no route matches, return a 404 status
const status = { path: req.params[0], status: 404 };
res.status(404).send(status);
},
};
const redisKey = (userId) => {
return `user-map-${userId}`;
};
const axioshelper = (message, config, callback, retries = 3, delay = 100) => {
return new Promise(async (resolve, reject) => {
for (let i = 0; i < retries; i++) {
try {
const response = await axios(config);
console.log({ response: response });
if (response.status < 200 || response.status > 299) {
if (callback) {
await callback();
} else {
throw new Error(
`Axios Request failed! ${JSON.stringify(response)}`
);
}
}
resolve(response);
break;
} catch (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log("Error", error.message);
}
console.log(error.config);
if (i === retries - 1) {
if (callback) {
await callback();
}
console.log({
retry: i + 1,
error: "out of retries",
message,
url: config.url,
});
reject(error);
} else {
console.log({
level: "warn",
message: `Attempt ${i + 1} failed.`,
url: config.url,
});
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
}
});
};
app.route("^(?:/userId/([^/]+))(?:/$)?$", async (req, res, match) => {
try {
console.log("Received request for userId:", match[1]);
const modelName =
req.params?.modelName || proactive_agent_settings.modelName;
if (match.length > 1) {
const userId = match[1];
const smStr = redisKey(userId);
const sessionMap = await redis.hGetAll(smStr);
const metadata = {
userId: bot_user.userId,
};
const recognizedData = await axios
.post(
`${settings_667ef98d3ee8930a5debcbdb.nlu.apiBaseURL}Model/run/${req.params.workspaceId}/${req.params.branch}/${modelName}`,
{
input: req.body.input,
conversationId: sessionMap.conversationId,
settings: settings_667ef98d3ee8930a5debcbdb.nlu.settings,
metadata: metadata,
}
)
.then((response) => {
return response.data;
})
.catch((error) => {
//If we have error handling turned off, don't record the error
if (settings_667ef98d3ee8930a5debcbdb.errorHandling === false) {
throw error;
} else {
// Conversation ID is generated by the NLU
// Must make sure Conversation ID is created properly for an error transaction
// Get it from session map if it exists, or generate it if we got the error at the very first transaction.
const conversationId = sessionMap.conversationId || uuidv4();
let errorPayload = {
id: uuidv4(),
workspaceId: req.params.workspaceId,
errorInfo: {
name: error.name,
message: error.message,
stack: error.stack,
},
conversationId,
input: req.body.input,
answers: [settings_667ef98d3ee8930a5debcbdb.responses.modelError],
req: {
params: req.params,
query: req.query,
body: req.body,
headers: req.headers,
},
metadata,
classificationResults: [
{
label: "Model Error",
value: 0.0,
},
],
nerResults: {
entities: [],
sourceEntities: [],
},
// Reporting tags to match GlobalSupport function reporting
tag: "ERROR",
reporting: {
tag: "ERROR",
modelResponse: "ERROR",
},
};
// Add model name
errorPayload.req.params.route = modelName;
//add any other details you wish to see in transaction data
return errorPayload;
}
});
// console.log(recognizedData);
if (recognizedData.conversationId) {
await redis.hSet(
smStr,
"conversationId",
recognizedData.conversationId
);
await redis.expire(smStr, 3600);
if (sessionMap.conversationId) {
} else {
db.analytics.addConversation({
id: recognizedData.conversationId,
});
}
}
recognizedData._id = (
await db.analytics.addTransaction(recognizedData)
).insertedId;
// Send Answers to Messenger
new Promise(async (resolve) => {
for (const [index, answer] of recognizedData.answers.entries()) {
try {
await axios.post(
`${settings_667ef98d3ee8930a5debcbdb.messenger.apiBaseURL}Event/create`,
{
conversationId: sessionMap.sessionId,
metadata: {
channel: "web",
},
input: answer,
sentBy: bot_user,
ping: nanoid(),
sentAt: Date.now(),
options: recognizedData?.options,
metadata: {
outputs:
recognizedData.answers.length == index + 1
? recognizedData?.outputs
: {},
transactionId: recognizedData._id,
feedbackable: false,
},
},
{
headers: {
Authorization: `Bearer ${settings_667ef98d3ee8930a5debcbdb.messenger.token}`,
},
}
);
} catch (e) {}
}
resolve(true);
});
res.send(recognizedData);
} else {
res.status(400).send({ error: "Bad Request" });
}
} catch (error) {
console.error(error);
return res.status(500).send({
status: 500,
});
}
});
app.route("/", async (req, res) => {
const sessionId = req.body.event?.conversationId;
const params = req.body.event?.params || {};
const modelName =
params?.modelName || settings_667ef98d3ee8930a5debcbdb.nlu.modelName;
const env = params?.env;
const postBack = req.body.event?.postBack;
const metadata = {
...req.body.event?.metadata,
userId: req.body.event?.sentBy?.userId,
};
const configuration = req.body.event?.configuration;
try {
const umStr = redisKey(metadata.userId);
await redis.hSet(umStr, "sessionId", sessionId);
await redis.expire(umStr, 3600);
await axioshelper("messenger join", {
method: "post",
url: `${msgrSettings.messenger.apiBaseURL}Conversation/join`,
headers: studioToken,
data: {
_id: sessionId,
participant: bot_user,
},
});
res.send();
} catch (error) {
console.log(error.message);
res.send({
answers: ["Something went wrong. Please try again."],
outputs: {},
});
}
});
app.run(req, res);

View File

@ -0,0 +1,25 @@
// Add this code to the Messenger's 'On Engagement Load' block
window.askIVA = (input, postBack, metadata, configuration) => {
// store.main.showMessenger();
// store.main.setView("chat");
// store.main.setNcPing(crypto.randomUUID());
store.conversationEvent.sendMessage({
input,
postBack,
metadata,
configuration,
});
};
// Set form when messenger is opened
vm.$watch(
() => store.main.newConversation,
async (value) => {
if (value) {
console.log("Starting New Conversation...");
setTimeout(() => {
window.askIVA("Digital Wecome Event");
}, 100);
}
}
);

View File

@ -0,0 +1,17 @@
(async () => {
proactive_agent.joinConversation(conversationData.id);
})()
.catch((error) => {
console.log(error.message);
recognizedObject.answers.push("");
recognizedObject.errorInfo = {
...recognizedObject.errorInfo,
label: {
data: error.toJSON ? error.toJSON() : {},
message: error.message,
},
};
})
.finally(() => {
next();
});