Files
anything-llm/server/utils/agents/aibitat/plugins/cli.js
Marcello Fitton 4a4378ed99 chore: add ESLint to /server (#5126)
* add eslint config to server

* add break statements to switch case

* add support for browser globals and turn off empty catch blocks

* disable lines with useless try/catch wrappers

* format

* fix no-undef errors

* disbale lines violating no-unsafe-finally

* ignore syncStaticLists.mjs

* use proper null check for creatorId instead of unreachable nullish coalescing

* remove unneeded typescript eslint comment

* make no-unused-private-class-members a warning

* disable line for no-empty-objects

* add new lint script

* fix no-unused-vars violations

* make no-unsued-vars an error

---------

Co-authored-by: shatfield4 <seanhatfield5@gmail.com>
Co-authored-by: Timothy Carambat <rambat1010@gmail.com>
2026-03-05 16:32:45 -08:00

135 lines
3.9 KiB
JavaScript

// Plugin CAN ONLY BE USE IN DEVELOPMENT.
const { input } = require("@inquirer/prompts");
const chalk = require("chalk");
/**
* Command-line Interface plugin. It prints the messages on the console and asks for feedback
* while the conversation is running in the background.
*/
const cli = {
name: "cli",
startupConfig: {
params: {},
},
plugin: function ({ simulateStream = true } = {}) {
return {
name: this.name,
setup(aibitat) {
let printing = [];
aibitat.onError(async (error) => {
let errorMessage =
error?.message || "An error occurred while running the agent.";
console.error(chalk.red(` error: ${errorMessage}`), error);
});
aibitat.onStart(() => {
console.log();
console.log("🚀 starting chat ...\n");
printing = [Promise.resolve()];
});
aibitat.onMessage(async (message) => {
const next = new Promise(async (resolve) => {
await Promise.all(printing);
await this.print(message, simulateStream);
resolve();
});
printing.push(next);
});
aibitat.onTerminate(async () => {
await Promise.all(printing);
console.log("🚀 chat finished");
});
aibitat.onInterrupt(async (node) => {
await Promise.all(printing);
const feedback = await this.askForFeedback(node);
// Add an extra line after the message
console.log();
if (feedback === "exit") {
console.log("🚀 chat finished");
return process.exit(0);
}
await aibitat.continue(feedback);
});
},
/**
* Print a message on the terminal
*
* @param message
* // message Type { from: string; to: string; content?: string } & {
state: 'loading' | 'error' | 'success' | 'interrupt'
}
* @param simulateStream
*/
print: async function (message = {}, simulateStream = true) {
const replying = chalk.dim(`(to ${message.to})`);
const reference = `${chalk.magenta("✎")} ${chalk.bold(
message.from
)} ${replying}:`;
if (!simulateStream) {
console.log(reference);
console.log(message.content);
// Add an extra line after the message
console.log();
return;
}
process.stdout.write(`${reference}\n`);
// Emulate streaming by breaking the cached response into chunks
const chunks = message.content?.split(" ") || [];
const stream = new ReadableStream({
async start(controller) {
for (const chunk of chunks) {
const bytes = new TextEncoder().encode(chunk + " ");
controller.enqueue(bytes);
await new Promise((r) =>
setTimeout(
r,
// get a random number between 10ms and 50ms to simulate a random delay
Math.floor(Math.random() * 40) + 10
)
);
}
controller.close();
},
});
// Stream the response to the chat
for await (const chunk of stream) {
process.stdout.write(new TextDecoder().decode(chunk));
}
// Add an extra line after the message
console.log();
console.log();
},
/**
* Ask for feedback to the user using the terminal
*
* @param node //{ from: string; to: string }
* @returns
*/
askForFeedback: function (node = {}) {
return input({
message: `Provide feedback to ${chalk.yellow(
node.to
)} as ${chalk.yellow(
node.from
)}. Press enter to skip and use auto-reply, or type 'exit' to end the conversation: `,
});
},
};
},
};
module.exports = { cli };