How to reset the graph state property? #38

Closed
opened 2026-02-15 17:05:59 -05:00 by yindo · 3 comments
Owner

Originally created by @s97712 on GitHub (Jun 20, 2024).

This is my state definition

interface IState {
  // Messages generated during the agent process, only keep the result and put into the history
  messages: BaseMessage[];
  history: BaseMessage[];
}

const graphState: StateGraphArgs<IState>["channels"] = {
  messages: {
    reducer: (a, b) => [...a, ...b],
    default: () => [],
  },
  history: {
    reducer: (a, b) => [...a, ...b],
    default: () => []
  },
};

I want to reset the messages after the agent process, and put the output into history.

But after hours of hard work, I found that all the ways to set state go through the reducer, and I can't directly set state to a certain value.

Can you provide a way to set the state without going through the'reducer ', so that we can reset the state?

Originally created by @s97712 on GitHub (Jun 20, 2024). This is my state definition ```ts interface IState { // Messages generated during the agent process, only keep the result and put into the history messages: BaseMessage[]; history: BaseMessage[]; } const graphState: StateGraphArgs<IState>["channels"] = { messages: { reducer: (a, b) => [...a, ...b], default: () => [], }, history: { reducer: (a, b) => [...a, ...b], default: () => [] }, }; ``` I want to reset the `messages` after the `agent` process, and put the output into `history`. But after hours of hard work, I found that all the ways to set state go through the `reducer`, and I can't directly set state to a certain value. Can you provide a way to set the state without going through the'reducer ', so that we can reset the state?
yindo closed this issue 2026-02-15 17:05:59 -05:00
Author
Owner

@hwchase17 commented on GitHub (Jun 20, 2024):

currently everything must go through the reducer

@hwchase17 commented on GitHub (Jun 20, 2024): currently everything must go through the reducer
Author
Owner

@hinthornw commented on GitHub (Jun 20, 2024):

Hi @s97712 would love to hear more about your use case. The ways I do it depend on the context.

  1. Reset full state: In many cases, I would just start a new thread (if indeed this is meant to start a new interaction). The old thread is no longer needed.
  2. Reset specific values: I'd let the reducer also accept something like a "Delete" type. Something like the following pseudocode:
type reduceOperation = {
     action: "delete"
}
function reduceMessages(a?: BaseMessage[] , b?: BaseMessage[] | reduceOperation) -> BaseMessage[]{
     if (b?.action === "delete") {
         return []
     }
     return [...a, ...b];
}

const graphState: StateGraphArgs<IState>["channels"] = {
  messages: {
    reducer: (a, b) => [...a, ...b],
    default: () => [],
  },
  history: {
    reducer: (a, b) => [...a, ...b],
    default: () => []
  },
};
@hinthornw commented on GitHub (Jun 20, 2024): Hi @s97712 would love to hear more about your use case. The ways I do it depend on the context. 1. Reset full state: In many cases, I would just start a new thread (if indeed this is meant to start a new interaction). The old thread is no longer needed. 2. Reset specific values: I'd let the reducer also accept something like a "Delete" type. Something like the following pseudocode: ``` type reduceOperation = { action: "delete" } function reduceMessages(a?: BaseMessage[] , b?: BaseMessage[] | reduceOperation) -> BaseMessage[]{ if (b?.action === "delete") { return [] } return [...a, ...b]; } const graphState: StateGraphArgs<IState>["channels"] = { messages: { reducer: (a, b) => [...a, ...b], default: () => [], }, history: { reducer: (a, b) => [...a, ...b], default: () => [] }, }; ```
Author
Owner

@gabrieljablonski commented on GitHub (Oct 9, 2024):

not exactly the issue from the OP, but I ran into the similar problem of not being able to simply fully reset the state for a thread.

the RemoveMessage pattern doesn't seem to work at all in my workflow.

until there's a direct way to just drop the state for a specific thread id, my current workaround when using the postgres checkpointer is to run the deletes manually on each of the checkpoint tables.

import { Pool } from "pg";
import { PostgresSaver } from "@langchain/langgraph-checkpoint-postgres";

// Workflow setup
const workflow = new StateGraph(...)

// Checkpointer + compile
const pool = new Pool(...);
const checkpointer = new PostgresSaver(pool);
// NOTE: Call on first run to setup the database
// await checkpointer.setup();
const app = workflow.compile({ checkpointer });

// Whatever else you need to do
// ...

function resetThread(threadId: string) {
  return Promise.allSettled([
    pool.query("DELETE FROM checkpoints WHERE thread_id = $1", [threadId]),
    pool.query("DELETE FROM checkpoint_blobs WHERE thread_id = $1", [threadId]),
    pool.query("DELETE FROM checkpoint_writes WHERE thread_id = $1", [
      threadId,
    ]),
  ]);
}

should be applicable to other checkpointers as well (I think mysql and redis are the other natively supported ones?)

far from ideal, but solves my problem for now.

@gabrieljablonski commented on GitHub (Oct 9, 2024): not exactly the issue from the OP, but I ran into the similar problem of not being able to simply fully reset the state for a thread. the `RemoveMessage` pattern doesn't seem to work at all in my workflow. until there's a direct way to just drop the state for a specific thread id, my current workaround when using the postgres checkpointer is to run the deletes manually on each of the checkpoint tables. ```ts import { Pool } from "pg"; import { PostgresSaver } from "@langchain/langgraph-checkpoint-postgres"; // Workflow setup const workflow = new StateGraph(...) // Checkpointer + compile const pool = new Pool(...); const checkpointer = new PostgresSaver(pool); // NOTE: Call on first run to setup the database // await checkpointer.setup(); const app = workflow.compile({ checkpointer }); // Whatever else you need to do // ... function resetThread(threadId: string) { return Promise.allSettled([ pool.query("DELETE FROM checkpoints WHERE thread_id = $1", [threadId]), pool.query("DELETE FROM checkpoint_blobs WHERE thread_id = $1", [threadId]), pool.query("DELETE FROM checkpoint_writes WHERE thread_id = $1", [ threadId, ]), ]); } ``` should be applicable to other checkpointers as well (I think mysql and redis are the other natively supported ones?) far from ideal, but solves my problem for now.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraphjs#38