improve components
This commit is contained in:
@@ -5,7 +5,6 @@ import { OpenCodeState, OpenCodeUpdate } from "../types";
|
||||
import { LangGraphRunnableConfig } from "@langchain/langgraph";
|
||||
import ComponentMap from "../../uis";
|
||||
import { typedUi } from "@langchain/langgraph-sdk/react-ui/server";
|
||||
import { PLAN } from "./planner";
|
||||
|
||||
export async function executor(
|
||||
state: OpenCodeState,
|
||||
@@ -18,11 +17,25 @@ export async function executor(
|
||||
m.getType() === "ai" &&
|
||||
(m as unknown as AIMessage).tool_calls?.some((tc) => tc.name === "plan"),
|
||||
) as AIMessage | undefined;
|
||||
const planToolCallArgs = lastPlanToolCall?.tool_calls?.[0]?.args?.args;
|
||||
const numOfExecutedPlanItems: number =
|
||||
planToolCallArgs?.executedPlans?.length ?? 0;
|
||||
const planToolCallArgs = lastPlanToolCall?.tool_calls?.[0]?.args as Record<
|
||||
string,
|
||||
any
|
||||
>;
|
||||
const nextPlanItem = planToolCallArgs?.remainingPlans?.[0] as
|
||||
| string
|
||||
| undefined;
|
||||
const numOfExecutedPlanItems = planToolCallArgs?.executedPlans?.length ?? 0;
|
||||
|
||||
const planItem = PLAN[numOfExecutedPlanItems - 1];
|
||||
if (!nextPlanItem) {
|
||||
// All plans have been executed
|
||||
const successfullyFinishedMsg: AIMessage = {
|
||||
type: "ai",
|
||||
id: uuidv4(),
|
||||
content:
|
||||
"Successfully completed all the steps in the plan. Please let me know if you need anything else!",
|
||||
};
|
||||
return { messages: [successfullyFinishedMsg] };
|
||||
}
|
||||
|
||||
let updateFileContents = "";
|
||||
switch (numOfExecutedPlanItems) {
|
||||
@@ -79,9 +92,8 @@ export async function executor(
|
||||
{
|
||||
name: "update_file",
|
||||
args: {
|
||||
args: {
|
||||
new_file_content: updateFileContents,
|
||||
},
|
||||
new_file_content: updateFileContents as any,
|
||||
executed_plan_item: nextPlanItem as any,
|
||||
},
|
||||
id: toolCallId,
|
||||
type: "tool_call",
|
||||
@@ -92,7 +104,7 @@ export async function executor(
|
||||
ui.write("proposed-change", {
|
||||
toolCallId,
|
||||
change: updateFileContents,
|
||||
planItem,
|
||||
planItem: nextPlanItem,
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { LangGraphRunnableConfig } from "@langchain/langgraph";
|
||||
import ComponentMap from "../../uis";
|
||||
import { typedUi } from "@langchain/langgraph-sdk/react-ui/server";
|
||||
|
||||
export const PLAN = [
|
||||
const PLAN = [
|
||||
"Set up project scaffolding using Create React App and implement basic folder structure for components, styles, and utilities.",
|
||||
"Create reusable UI components for TodoItem, including styling with CSS modules.",
|
||||
"Implement state management using React Context to handle todo items, including actions for adding, updating, and deleting todos.",
|
||||
@@ -21,19 +21,36 @@ export async function planner(
|
||||
): Promise<OpenCodeUpdate> {
|
||||
const ui = typedUi<typeof ComponentMap>(config);
|
||||
|
||||
const lastUpdateCodeToolCall = state.messages.findLast(
|
||||
(m) =>
|
||||
m.getType() === "ai" &&
|
||||
(m as unknown as AIMessage).tool_calls?.some(
|
||||
(tc) => tc.name === "update_file",
|
||||
),
|
||||
) as AIMessage | undefined;
|
||||
const lastPlanToolCall = state.messages.findLast(
|
||||
(m) =>
|
||||
m.getType() === "ai" &&
|
||||
(m as unknown as AIMessage).tool_calls?.some((tc) => tc.name === "plan"),
|
||||
) as AIMessage | undefined;
|
||||
const planToolCallArgs = lastPlanToolCall?.tool_calls?.[0]?.args?.args;
|
||||
const executedPlans = planToolCallArgs?.executedPlans ?? [];
|
||||
const remainingPlans = planToolCallArgs?.remainingPlans ?? PLAN;
|
||||
|
||||
const content =
|
||||
executedPlans.length > 0
|
||||
? `I've updated the plan list based on the executed plans.`
|
||||
: `I've come up with a detailed plan for building the todo app.`;
|
||||
const planToolCallArgs = lastPlanToolCall?.tool_calls?.[0]?.args as Record<
|
||||
string,
|
||||
any
|
||||
>;
|
||||
const executedPlans: string[] = planToolCallArgs?.executedPlans ?? [];
|
||||
let remainingPlans: string[] = planToolCallArgs?.remainingPlans ?? PLAN;
|
||||
|
||||
const executedPlanItem = lastUpdateCodeToolCall?.tool_calls?.[0]?.args
|
||||
?.executed_plan_item as string | undefined;
|
||||
if (executedPlanItem) {
|
||||
executedPlans.push(executedPlanItem);
|
||||
remainingPlans = remainingPlans.filter((p) => p !== executedPlanItem);
|
||||
}
|
||||
|
||||
const content = executedPlanItem
|
||||
? `I've updated the plan list based on the executed plans.`
|
||||
: `I've come up with a detailed plan for building the todo app.`;
|
||||
|
||||
const toolCallId = uuidv4();
|
||||
const aiMessage: AIMessage = {
|
||||
@@ -44,10 +61,8 @@ export async function planner(
|
||||
{
|
||||
name: "plan",
|
||||
args: {
|
||||
args: {
|
||||
executedPlans,
|
||||
remainingPlans,
|
||||
},
|
||||
executedPlans,
|
||||
remainingPlans,
|
||||
},
|
||||
id: toolCallId,
|
||||
type: "tool_call",
|
||||
|
||||
@@ -8,9 +8,9 @@ interface PlanProps {
|
||||
|
||||
export default function Plan(props: PlanProps) {
|
||||
return (
|
||||
<div className="flex flex-col gap-4 w-full max-w-xl p-6 border-[1px] rounded-xl border-slate-500">
|
||||
<div className="flex flex-col gap-4 w-full max-w-4xl p-6 border-[1px] rounded-xl border-slate-500">
|
||||
<h2 className="text-2xl font-semibold text-center mb-2">Code Plan</h2>
|
||||
<div className="grid grid-cols-2 divide-x divide-slate-300">
|
||||
<div className="grid grid-cols-2 divide-x divide-slate-300 w-full">
|
||||
<div className="flex flex-col gap-2 pr-6">
|
||||
<h3 className="text-lg font-medium mb-4 text-slate-700">
|
||||
Executed Plans
|
||||
|
||||
@@ -7,7 +7,8 @@ import { coldarkDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
|
||||
import { UIMessage, useStreamContext } from "@langchain/langgraph-sdk/react-ui";
|
||||
import { Message } from "@langchain/langgraph-sdk";
|
||||
import { DO_NOT_RENDER_ID_PREFIX } from "@/lib/ensure-tool-responses";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { getToolResponse } from "../../utils/get-tool-response";
|
||||
|
||||
interface ProposedChangeProps {
|
||||
toolCallId: string;
|
||||
@@ -15,6 +16,9 @@ interface ProposedChangeProps {
|
||||
planItem: string;
|
||||
}
|
||||
|
||||
const ACCEPTED_CHANGE_CONTENT =
|
||||
"User accepted the proposed change. Please continue.";
|
||||
|
||||
export default function ProposedChange(props: ProposedChangeProps) {
|
||||
const [isAccepted, setIsAccepted] = useState(false);
|
||||
|
||||
@@ -27,7 +31,6 @@ export default function ProposedChange(props: ProposedChangeProps) {
|
||||
alert("Rejected. (just kidding, you can't reject me silly!)");
|
||||
};
|
||||
const handleAccept = () => {
|
||||
const content = "User accepted the proposed change. Please continue.";
|
||||
thread.submit({
|
||||
messages: [
|
||||
{
|
||||
@@ -35,7 +38,7 @@ export default function ProposedChange(props: ProposedChangeProps) {
|
||||
tool_call_id: props.toolCallId,
|
||||
id: `${DO_NOT_RENDER_ID_PREFIX}${uuidv4()}`,
|
||||
name: "buy-stock",
|
||||
content,
|
||||
content: ACCEPTED_CHANGE_CONTENT,
|
||||
},
|
||||
{
|
||||
type: "human",
|
||||
@@ -47,9 +50,17 @@ export default function ProposedChange(props: ProposedChangeProps) {
|
||||
setIsAccepted(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined" || isAccepted) return;
|
||||
const toolResponse = getToolResponse(props.toolCallId, thread);
|
||||
if (toolResponse && toolResponse.content === ACCEPTED_CHANGE_CONTENT) {
|
||||
setIsAccepted(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (isAccepted) {
|
||||
return (
|
||||
<div className="flex flex-col gap-4 w-full max-w-xl p-4 border-[1px] rounded-xl border-green-300">
|
||||
<div className="flex flex-col gap-4 w-full max-w-4xl p-4 border-[1px] rounded-xl border-green-300">
|
||||
<div className="flex flex-col items-start justify-start gap-2">
|
||||
<p className="text-lg font-medium">Accepted Change</p>
|
||||
<p className="text-sm font-mono">{props.planItem}</p>
|
||||
|
||||
Reference in New Issue
Block a user