Files
agent-chat-ui/agent/open-code/nodes/executor.ts

126 lines
3.3 KiB
TypeScript
Raw Normal View History

2025-03-07 10:47:08 -08:00
import fs from "fs/promises";
import { v4 as uuidv4 } from "uuid";
import { AIMessage } from "@langchain/langgraph-sdk";
2025-03-06 20:04:55 -08:00
import { OpenCodeState, OpenCodeUpdate } from "../types";
2025-03-07 10:47:08 -08:00
import { LangGraphRunnableConfig } from "@langchain/langgraph";
import ComponentMap from "../../uis";
import { typedUi } from "@langchain/langgraph-sdk/react-ui/server";
2025-03-06 20:04:55 -08:00
export const SUCCESSFULLY_COMPLETED_STEPS_CONTENT =
"Successfully completed all the steps in the plan. Please let me know if you need anything else!";
2025-03-07 10:47:08 -08:00
export async function executor(
state: OpenCodeState,
config: LangGraphRunnableConfig,
): Promise<OpenCodeUpdate> {
const ui = typedUi<typeof ComponentMap>(config);
2025-03-07 11:21:49 -08:00
const lastPlanToolCall = state.messages.findLast(
2025-03-07 10:47:08 -08:00
(m) =>
m.getType() === "ai" &&
2025-03-07 11:21:49 -08:00
(m as unknown as AIMessage).tool_calls?.some((tc) => tc.name === "plan"),
) as AIMessage | undefined;
2025-03-07 12:43:22 -08:00
const planToolCallArgs = lastPlanToolCall?.tool_calls?.[0]?.args as Record<
string,
any
>;
const nextPlanItem = planToolCallArgs?.remainingPlans?.[0] as
| string
| undefined;
const numSeenPlans =
[
...(planToolCallArgs?.executedPlans ?? []),
...(planToolCallArgs?.rejectedPlans ?? []),
]?.length ?? 0;
2025-03-07 11:21:49 -08:00
2025-03-07 12:43:22 -08:00
if (!nextPlanItem) {
// All plans have been executed
const successfullyFinishedMsg: AIMessage = {
type: "ai",
id: uuidv4(),
content: SUCCESSFULLY_COMPLETED_STEPS_CONTENT,
2025-03-07 12:43:22 -08:00
};
return { messages: [successfullyFinishedMsg] };
}
2025-03-07 10:47:08 -08:00
let updateFileContents = "";
switch (numSeenPlans) {
2025-03-07 10:47:08 -08:00
case 0:
updateFileContents = await fs.readFile(
"agent/open-code/nodes/plan-code/step-1.txt",
"utf-8",
);
break;
case 1:
updateFileContents = await fs.readFile(
"agent/open-code/nodes/plan-code/step-2.txt",
"utf-8",
);
break;
case 2:
updateFileContents = await fs.readFile(
"agent/open-code/nodes/plan-code/step-3.txt",
"utf-8",
);
break;
case 3:
updateFileContents = await fs.readFile(
"agent/open-code/nodes/plan-code/step-4.txt",
"utf-8",
);
break;
case 4:
updateFileContents = await fs.readFile(
"agent/open-code/nodes/plan-code/step-5.txt",
"utf-8",
);
break;
case 5:
updateFileContents = await fs.readFile(
"agent/open-code/nodes/plan-code/step-6.txt",
"utf-8",
);
break;
default:
updateFileContents = "";
}
if (!updateFileContents) {
throw new Error("No file updates found!");
}
const toolCallId = uuidv4();
const aiMessage: AIMessage = {
type: "ai",
id: uuidv4(),
content: "",
tool_calls: [
{
name: "update_file",
args: {
2025-03-07 12:43:22 -08:00
new_file_content: updateFileContents as any,
executed_plan_item: nextPlanItem as any,
2025-03-07 10:47:08 -08:00
},
id: toolCallId,
type: "tool_call",
},
],
};
const fullWriteAccess = !!config.configurable?.permissions?.full_write_access;
2025-03-07 21:26:48 +01:00
const msg = ui.create("proposed-change", {
2025-03-07 10:47:08 -08:00
toolCallId,
change: updateFileContents,
2025-03-07 12:43:22 -08:00
planItem: nextPlanItem,
fullWriteAccess,
2025-03-07 10:47:08 -08:00
});
2025-03-07 21:26:48 +01:00
msg.additional_kwargs["message_id"] = aiMessage.id;
2025-03-07 10:47:08 -08:00
return {
messages: [aiMessage],
2025-03-07 21:26:48 +01:00
ui: [msg],
2025-03-07 10:47:08 -08:00
timestamp: Date.now(),
};
}