Harshith Mullapudi 00f983079f 1. Added onboarding
2. fix: remove custom tool calls in chat and link directly to mcp
2025-10-21 11:32:36 +05:30

151 lines
4.3 KiB
TypeScript

import { ActionStatusEnum } from "@core/types";
import { metadata, task, queue } from "@trigger.dev/sdk";
import { run } from "./chat-utils";
import { MCP } from "../utils/mcp";
import { type HistoryStep } from "../utils/types";
import {
createConversationHistoryForAgent,
deductCredits,
deletePersonalAccessToken,
getPreviousExecutionHistory,
hasCredits,
InsufficientCreditsError,
init,
type RunChatPayload,
updateConversationHistoryMessage,
updateConversationStatus,
updateExecutionStep,
} from "../utils/utils";
const chatQueue = queue({
name: "chat-queue",
concurrencyLimit: 50,
});
/**
* Main chat task that orchestrates the agent workflow
* Handles conversation context, agent selection, and LLM interactions
*/
export const chat = task({
id: "chat",
maxDuration: 3000,
queue: chatQueue,
init,
run: async (payload: RunChatPayload, { init }) => {
await updateConversationStatus("running", payload.conversationId);
try {
// Check if workspace has sufficient credits before processing
if (init?.conversation.workspaceId) {
const hasSufficientCredits = await hasCredits(
init.conversation.workspaceId,
"chatMessage",
);
if (!hasSufficientCredits) {
throw new InsufficientCreditsError(
"Insufficient credits to process chat message. Please upgrade your plan or wait for your credits to reset.",
);
}
}
const { previousHistory, ...otherData } = payload.context;
// Initialise mcp
const mcpHeaders = { Authorization: `Bearer ${init?.token}` };
const mcp = new MCP();
await mcp.init();
await mcp.load(mcpHeaders);
// Prepare context with additional metadata
const context = {
// Currently this is assuming we only have one page in context
context: {
...(otherData.page && otherData.page.length > 0
? { page: otherData.page[0] }
: {}),
},
workpsaceId: init?.conversation.workspaceId,
resources: otherData.resources,
todayDate: new Date().toISOString(),
};
// Extract user's goal from conversation history
const message = init?.conversationHistory?.message;
// Retrieve execution history from previous interactions
const previousExecutionHistory = getPreviousExecutionHistory(
previousHistory ?? [],
);
let agentUserMessage = "";
let agentConversationHistory;
let stepHistory: HistoryStep[] = [];
// Prepare conversation history in agent-compatible format
agentConversationHistory = await createConversationHistoryForAgent(
payload.conversationId,
);
const llmResponse = run(
message as string,
context,
previousExecutionHistory,
mcp,
stepHistory,
);
const stream = await metadata.stream("messages", llmResponse);
let conversationStatus = "success";
for await (const step of stream) {
if (step.type === "STEP") {
const stepDetails = JSON.parse(step.message as string);
if (stepDetails.skillStatus === ActionStatusEnum.TOOL_REQUEST) {
conversationStatus = "need_approval";
}
if (stepDetails.skillStatus === ActionStatusEnum.QUESTION) {
conversationStatus = "need_attention";
}
await updateExecutionStep(
{ ...stepDetails },
agentConversationHistory.id,
);
agentUserMessage += stepDetails.userMessage;
await updateConversationHistoryMessage(
agentUserMessage,
agentConversationHistory.id,
);
} else if (step.type === "STREAM_END") {
break;
}
}
await updateConversationStatus(
conversationStatus,
payload.conversationId,
);
// Deduct credits for chat message
if (init?.conversation.workspaceId) {
await deductCredits(init.conversation.workspaceId, "chatMessage");
}
if (init?.tokenId) {
await deletePersonalAccessToken(init.tokenId);
}
} catch (e) {
console.log(e);
await updateConversationStatus("failed", payload.conversationId);
if (init?.tokenId) {
await deletePersonalAccessToken(init.tokenId);
}
throw new Error(e as string);
}
},
});