2025-03-07 13:42:37 -08:00
|
|
|
import {
|
|
|
|
|
END,
|
|
|
|
|
LangGraphRunnableConfig,
|
|
|
|
|
START,
|
|
|
|
|
StateGraph,
|
|
|
|
|
} from "@langchain/langgraph";
|
|
|
|
|
import { OpenCodeAnnotation, OpenCodeState } from "./types";
|
2025-03-06 20:04:55 -08:00
|
|
|
import { planner } from "./nodes/planner";
|
2025-03-07 13:42:37 -08:00
|
|
|
import {
|
|
|
|
|
executor,
|
|
|
|
|
SUCCESSFULLY_COMPLETED_STEPS_CONTENT,
|
|
|
|
|
} from "./nodes/executor";
|
|
|
|
|
import { AIMessage } from "@langchain/langgraph-sdk";
|
|
|
|
|
|
|
|
|
|
function conditionallyEnd(
|
|
|
|
|
state: OpenCodeState,
|
|
|
|
|
config: LangGraphRunnableConfig,
|
|
|
|
|
): typeof END | "planner" {
|
|
|
|
|
const fullWriteAccess = !!config.configurable?.permissions?.full_write_access;
|
|
|
|
|
const lastAiMessage = state.messages.findLast(
|
|
|
|
|
(m) => m.getType() === "ai",
|
|
|
|
|
) as unknown as AIMessage;
|
|
|
|
|
|
|
|
|
|
// If the user did not grant full write access, or the last AI message is the success message, end
|
|
|
|
|
// otherwise, loop back to the start.
|
|
|
|
|
if (
|
|
|
|
|
(typeof lastAiMessage.content === "string" &&
|
|
|
|
|
lastAiMessage.content === SUCCESSFULLY_COMPLETED_STEPS_CONTENT) ||
|
|
|
|
|
!fullWriteAccess
|
|
|
|
|
) {
|
|
|
|
|
return END;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "planner";
|
|
|
|
|
}
|
2025-03-06 20:04:55 -08:00
|
|
|
|
|
|
|
|
const workflow = new StateGraph(OpenCodeAnnotation)
|
|
|
|
|
.addNode("planner", planner)
|
|
|
|
|
.addNode("executor", executor)
|
|
|
|
|
.addEdge(START, "planner")
|
|
|
|
|
.addEdge("planner", "executor")
|
2025-03-07 13:42:37 -08:00
|
|
|
.addConditionalEdges("executor", conditionallyEnd, ["planner", END]);
|
2025-03-07 10:47:08 -08:00
|
|
|
|
|
|
|
|
export const graph = workflow.compile();
|
|
|
|
|
graph.name = "Open Code Graph";
|