import "dotenv/config";
import readline from "node:readline/promises";
import { stdin as input, stdout as output } from "node:process";
import { Composio } from "@composio/core";
import { LlamaindexProvider } from "@composio/llamaindex";
import { mcp } from "@llamaindex/tools";
import { agent as createAgent } from "@llamaindex/workflow";
import { openai } from "@llamaindex/openai";
dotenv.config();
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
const COMPOSIO_API_KEY = process.env.COMPOSIO_API_KEY;
const COMPOSIO_USER_ID = process.env.COMPOSIO_USER_ID;
if (!OPENAI_API_KEY) {
throw new Error("OPENAI_API_KEY is not set in the environment");
}
if (!COMPOSIO_API_KEY) {
throw new Error("COMPOSIO_API_KEY is not set in the environment");
}
if (!COMPOSIO_USER_ID) {
throw new Error("COMPOSIO_USER_ID is not set in the environment");
}
async function buildAgent() {
console.log(`Initializing Composio client...${COMPOSIO_USER_ID!}...`);
console.log(`COMPOSIO_USER_ID: ${COMPOSIO_USER_ID!}...`);
const composio = new Composio({
apiKey: COMPOSIO_API_KEY,
provider: new LlamaindexProvider(),
});
const session = await composio.create(
COMPOSIO_USER_ID!,
{
toolkits: ["sensibo"],
},
);
const mcpUrl = session.mcp.url;
console.log(`Composio Tool Router MCP URL: ${mcpUrl}`);
const server = mcp({
url: mcpUrl,
clientName: "composio_tool_router_with_llamaindex",
requestInit: {
headers: {
"x-api-key": COMPOSIO_API_KEY!,
},
},
});
const tools = await server.tools();
const llm = openai({ apiKey: OPENAI_API_KEY, model: "gpt-5" });
const agent = createAgent({
name: "composio_tool_router_with_llamaindex",
description:
"An agent that uses Composio Tool Router MCP tools to perform actions.",
systemPrompt:
"You are a helpful assistant connected to Composio Tool Router."+
"Use the available tools to answer user queries and perform Sensibo actions." ,
llm,
tools,
});
return agent;
}
async function chatLoop(agent: ReturnType<typeof createAgent>) {
const rl = readline.createInterface({ input, output });
console.log("Type 'quit' or 'exit' to stop.");
while (true) {
let userInput: string;
try {
userInput = (await rl.question("\nYou: ")).trim();
} catch {
console.log("\nAgent: Bye!");
break;
}
if (!userInput) {
continue;
}
const lower = userInput.toLowerCase();
if (lower === "quit" || lower === "exit") {
console.log("Agent: Bye!");
break;
}
try {
process.stdout.write("Agent: ");
const stream = agent.runStream(userInput);
let finalResult: any = null;
for await (const event of stream) {
const data: any = event.data;
if (data?.delta) {
process.stdout.write(data.delta);
}
if (data?.result || data?.message) {
finalResult = data;
}
}
if (finalResult) {
const answer =
finalResult.result ??
finalResult.message?.content ??
finalResult.message ??
"";
if (answer && typeof answer === "string" && !answer.includes("[object")) {
process.stdout.write(answer);
}
}
console.log();
} catch (err: any) {
console.error("\nAgent error:", err?.message ?? err);
}
}
rl.close();
}
async function main() {
try {
const agent = await buildAgent();
await chatLoop(agent);
} catch (err: any) {
console.error("Failed to start agent:", err?.message ?? err);
process.exit(1);
}
}
main();