Postres Memory Chat node + context window summarization

Describe the problem/error/question

If my cutoff window for chat is 10, when the user hits chat 11, it means chat #1 is no longer in the context window. Essentially I’m working with a sliding window. Is there an example using a summarization technique with n8n on how to keep a longer chat history running knowing, the chat memory module will only keep the last 10 chats. Its kind of starts to get expensive if you are having to summarize after every chat once you get past 10

Information on your n8n setup

  • n8n version: lastest
  • Database : SupaBase
  • n8n EXECUTIONS_PROCESS setting (default: own, main):
  • Running n8n via n8n cloud.
  • Operating system: MAC OS

Hello SpencerB, thank you for asking! I’ll try to help yaa.

You’re right, with Postgres Memory Chat (or any chat memory) a cutoff of 10 gives you a sliding window. The fix is a hybrid memory, keep last 10 turns as short term, plus a rolling long-term summary you refresh only sometimes (not every turn).

How to set it up?

  1. Load short-term: Postgres Memory Chat (limit it to 10).
  2. Fetch long-term summary from Supabase table thread_summaries (by conversation_id)
  3. Build prompt to the model for system: “You have a running summary: <summary_so_far>”, context: last 10 turns from memory
  4. Answer normally.
  5. Occasionally summarize (every N turns or when tokens high), then upsert the new summary back to thread_summaries.

When to summarize? (so its not every turn)

Use a tiny Code node right after Memory to decide:

// inputs: last10 = items[0].json.last10Messages (array), meta = items[0].json.meta
const turn = (meta?.turn || 0) + 1;
const summarizeNow = (turn % 8 === 0); // summarize every 8 turns
return [{ json: { turn, summarizeNow } }];

Or trigger by size:

const totalChars = JSON.stringify($json.last10Messages || []).length;
const summarizeNow = totalChars > 6000; // rough ~1.5k tokens
return [{ json: { summarizeNow } }];

The summarization step (only if summarizeNow)

  • Prompt (concise, composes well):

“Summarize the conversation so far into 8–12 bullet points. Keep entities, intents, decisions, open TODOs. No fluff. Output <= 800 chars.”

  • Write back:
    • Read old summary_so_far from Supabase.
    • New summary = compress(old_summary = last10)
    • Upsert {conversation_id, summary_so_far, updated_at}

I have minimal Supabase schema that maybe you can try:

create table if not exists thread_summaries (
  conversation_id text primary key,
  summary_so_far  text not null,
  updated_at      timestamptz default now()
);

Thats all i think i can share for now, i hope this answer will give you a solution. Always keep up the spirit :fire:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.