From 7884ad4090de12fe9a0bccc27600a8dd12f1afd7 Mon Sep 17 00:00:00 2001 From: bracesproul Date: Tue, 7 Jan 2025 11:13:35 -0800 Subject: [PATCH 1/2] fix: Handle invalid human responses --- .../generate-post/generate-post-graph.ts | 12 ++++++- .../generate-post/generate-post-state.ts | 1 + .../generate-post/nodes/human-node/index.ts | 34 +++++++++++++++++-- .../nodes/human-node/route-response.ts | 16 +++++++-- .../generate-post/nodes/rewrite-post.ts | 1 + 5 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/agents/generate-post/generate-post-graph.ts b/src/agents/generate-post/generate-post-graph.ts index 20f04a5..2457738 100644 --- a/src/agents/generate-post/generate-post-graph.ts +++ b/src/agents/generate-post/generate-post-graph.ts @@ -26,8 +26,17 @@ function routeAfterGeneratingReport( function rewriteOrEndConditionalEdge( state: typeof GeneratePostAnnotation.State, -): "rewritePost" | "schedulePost" | "updateScheduleDate" | typeof END { +): + | "rewritePost" + | "schedulePost" + | "updateScheduleDate" + | "humanNode" + | typeof END { if (state.next) { + if (state.next === "unknownResponse") { + // If the user's response is unknown, we should route back to the human node. + return "humanNode"; + } return state.next; } return END; @@ -120,6 +129,7 @@ const generatePostBuilder = new StateGraph( "rewritePost", "schedulePost", "updateScheduleDate", + "humanNode", END, ]) // Always end after scheduling the post. diff --git a/src/agents/generate-post/generate-post-state.ts b/src/agents/generate-post/generate-post-state.ts index f15e1fc..b7cdc19 100644 --- a/src/agents/generate-post/generate-post-state.ts +++ b/src/agents/generate-post/generate-post-state.ts @@ -66,6 +66,7 @@ export const GeneratePostAnnotation = Annotation.Root({ | "schedulePost" | "rewritePost" | "updateScheduleDate" + | "unknownResponse" | typeof END | undefined >, diff --git a/src/agents/generate-post/nodes/human-node/index.ts b/src/agents/generate-post/nodes/human-node/index.ts index 5cd1a27..db901aa 100644 --- a/src/agents/generate-post/nodes/human-node/index.ts +++ b/src/agents/generate-post/nodes/human-node/index.ts @@ -10,6 +10,7 @@ import { import { routeResponse } from "./route-response.js"; interface ConstructDescriptionArgs { + unknownResponseDescription: string; report: string; originalLink: string; relevantLinks: string[]; @@ -18,6 +19,7 @@ interface ConstructDescriptionArgs { } function constructDescription({ + unknownResponseDescription, report, originalLink, relevantLinks, @@ -29,7 +31,10 @@ function constructDescription({ ? `## Image Options\n\nThe following image options are available. Select one by copying and pasting the URL into the 'image' field.\n\n${imageOptions.map((url) => `URL: ${url}\nImage:
Click to view image\n\n![](${url})\n
\n`).join("\n")}` : ""; - return `# Schedule post + const unknownResponseString = unknownResponseDescription + ? `${unknownResponseDescription}\n\n` + : ""; + return `${unknownResponseString}# Schedule post Using these URL(s), a post was generated for Twitter/LinkedIn: ${linksText} @@ -48,6 +53,7 @@ There are a few different actions which can be taken:\n - **Response**: If a response is sent, it will be sent to a router which can be routed to either 1. A node which will be used to rewrite the post. Please note, the response will be used as the 'user' message in an LLM call to rewrite the post, so ensure your response is properly formatted. 2. A node which will be used to update the scheduled date for the post. + If an unknown/invalid response is sent, nothing will happen, and it will be routed back to the human node. - **Accept**: If 'accept' is selected, the post will be scheduled for Twitter/LinkedIn. - **Ignore**: If 'ignore' is selected, this post will not be scheduled, and the thread will end. @@ -76,6 +82,21 @@ Here is the report that was generated for the posts:\n${report} `; } +const getUnknownResponseDescription = ( + state: typeof GeneratePostAnnotation.State, +) => { + if (state.next === "unknownResponse" && state.userResponse) { + return `#
UNKNOWN/INVALID RESPONSE RECEIVED: '${state.userResponse}'
+ +
Please respond with either a request to update/rewrite the post, or a valid priority level or a date to schedule the post.
+ +
See the \`Schedule Date\`, or \`Instructions\` sections for more information.
+ +
`; + } + return ""; +}; + export async function humanNode( state: typeof GeneratePostAnnotation.State, _config: LangGraphRunnableConfig, @@ -84,6 +105,7 @@ export async function humanNode( throw new Error("No post found"); } + const unknownResponseDescription = getUnknownResponseDescription(state); const defaultDate = state.scheduleDate || getNextSaturdayDate(); let defaultDateString = ""; if ( @@ -121,6 +143,7 @@ export async function humanNode( relevantLinks: state.relevantLinks, post: state.post, imageOptions: state.imageOptions, + unknownResponseDescription, }), }; @@ -161,10 +184,16 @@ export async function humanNode( next: "rewritePost", }; } + if (route === "update_date") { + return { + userResponse: response.args, + next: "updateScheduleDate", + }; + } return { userResponse: response.args, - next: "updateScheduleDate", + next: "unknownResponse", }; } @@ -213,5 +242,6 @@ export async function humanNode( next: "schedulePost", scheduleDate: postDate, image: imageState, + userResponse: undefined, }; } diff --git a/src/agents/generate-post/nodes/human-node/route-response.ts b/src/agents/generate-post/nodes/human-node/route-response.ts index dba3a2d..59a85ab 100644 --- a/src/agents/generate-post/nodes/human-node/route-response.ts +++ b/src/agents/generate-post/nodes/human-node/route-response.ts @@ -24,7 +24,9 @@ Carefully analyze the user's response: Based on the user's response, determine which of the two routes they intend to take. Consider the following: 1. If the user mentions editing, changing, or rewriting the content of the post, choose the "rewrite_post" route. -2. If the user mentions changing the date, time, or priority level of the post, choose the "update_date" route. +2. If the user mentions changing the date, time, or priority level of the post, choose the "update_date" route. Ensure you only call this if the user mentions a date, or one of P1, P2 or P3. + +If the user's response can not be handled by one of the two routes, choose the "unknown_response" route. Provide your answer in the following format: @@ -49,6 +51,16 @@ User: "This should be a P1 priority." Route: update_date Explanation: The user wants to change the priority level of the post. +Example 3: +User: "This should be a P0 priority." +Route: unknown_response +Explanation: P0 is not a valid priority level. + +Example 3: +User: "Hi! How are you?" +Route: unknown_response +Explanation: The user is engaging in general conversation, not a request to change the post. + Remember to always base your decision on the actual content of the user's response, not on these examples.`; interface RouteResponseArgs { @@ -68,7 +80,7 @@ export async function routeResponse({ }); const routeSchema = z.object({ - route: z.enum(["rewrite_post", "update_date"]), + route: z.enum(["rewrite_post", "update_date", "unknown_response"]), }); const modelWithSchema = model.withStructuredOutput(routeSchema, { name: "route", diff --git a/src/agents/generate-post/nodes/rewrite-post.ts b/src/agents/generate-post/nodes/rewrite-post.ts index 51365dc..5845ece 100644 --- a/src/agents/generate-post/nodes/rewrite-post.ts +++ b/src/agents/generate-post/nodes/rewrite-post.ts @@ -103,5 +103,6 @@ export async function rewritePost( return { post: revisePostResponse.content as string, next: undefined, + userResponse: undefined, }; } From 662c621dbfeab0881fe4eb2169eef61c396531f3 Mon Sep 17 00:00:00 2001 From: bracesproul Date: Tue, 7 Jan 2025 11:14:29 -0800 Subject: [PATCH 2/2] cr --- src/agents/generate-post/nodes/human-node/route-response.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/agents/generate-post/nodes/human-node/route-response.ts b/src/agents/generate-post/nodes/human-node/route-response.ts index 59a85ab..4a664e8 100644 --- a/src/agents/generate-post/nodes/human-node/route-response.ts +++ b/src/agents/generate-post/nodes/human-node/route-response.ts @@ -51,12 +51,12 @@ User: "This should be a P1 priority." Route: update_date Explanation: The user wants to change the priority level of the post. -Example 3: +Example 4: User: "This should be a P0 priority." Route: unknown_response Explanation: P0 is not a valid priority level. -Example 3: +Example 5: User: "Hi! How are you?" Route: unknown_response Explanation: The user is engaging in general conversation, not a request to change the post.