• Product Introduction
  • Quick Start
    • Agent Development
    • Importing a Git Repository
    • Starting From a Template
    • Direct Upload
    • Start with AI
  • Framework Guide
    • Agent
    • Frontends
      • Vite
      • React
      • Vue
      • Hugo
      • Other Frameworks
    • Backends
    • Full-stack
      • Next.js
      • Nuxt
      • Astro
      • React Router
      • SvelteKit
      • TanStack Start
      • Vike
    • Custom 404 Page
  • Project Guide
    • Project Management
    • edgeone.json
    • Configuring Cache
    • Building Output Configuration
    • Domain Management
      • Overview
      • Custom Domain
      • HTTPS Configuration
        • Overview
        • Apply for Free Certificate
        • Using Managed SSL Certificate
      • Configure DNS CNAME Record
    • Error Codes
  • Build Guide
  • Deployment Guide
    • Overview
    • Create Deploys
    • Manage Deploys
    • Deploy Button
    • Using Github Actions
    • Using Gitlab CI/CD
    • Using CNB Plugin
    • Using IDE PlugIn
    • Using CodeBuddy IDE
  • Makers for Platforms
    • Platform and Multi-Tenancy
    • Vibe Coding Solution
    • Template Example
      • Vibe Coding General Template
  • Observability
    • Overview
    • Metric Analysis
    • Log Analysis
  • Functions
    • Overview
    • Edge Functions
    • Cloud Functions
      • Overview
      • Node.js
      • Python
      • Go
  • Agents
    • Overview
    • Quick Start
    • Conversation Management
    • Observability
    • Sandbox Tool
      • Overview
      • Using the Agent Framework
      • Sandbox Atomic API
      • Network Search Tool
    • Agent Authentication
  • Models
    • Overview
    • Models and Vendors
      • Overview
      • Using the Zhuque Model
      • Using Vendor Keys
        • OpenAI
        • Anthropic
        • Google AI Studio
        • DeepSeek
        • MiniMax
        • Hunyuan
        • Zhipu
        • MoonShot AI
    • FAQs
  • Storage
    • Overview
    • KV
    • Blob
  • Middleware
  • AI-Native Development
    • Skills
    • MCP
    • Plugin
  • Copilot
    • Overview
    • Quick Start
  • API Token
  • EdgeOne CLI
  • Makers SDK
    • Overview
    • Examples
      • Creating a Deployment
      • Project Management
    • Projects
      • Project Operations
      • Environment Variable
    • Deployment
  • Message Notification
  • Integration Guide
    • AI
      • Makers Models Integration
      • Large Models for Images Integration
    • Database
      • Supabase Integration
      • Pages KV Integration
    • Ecommerce
      • Shopify Integration
      • WooCommerce Integration
    • Payment
      • Stripe Integration
      • Integrating Paddle
    • CMS
      • WordPress Integration
      • Contentful Integration
      • Sanity Integration
      • Payload Integration
    • Authentication
      • Supabase Integration
      • Clerk Integration
  • Best Practices
    • Adding an AI Chat Assistant to a Website
    • AI Dialogue Deployment: Deploy Project with One Sentence Using Skill
    • Building Agent Applications Quickly with Makers Agents
    • Building an Ecommerce Platform with Shopify
    • Building a SaaS Site Using Supabase and Stripe
    • Building a Company Brand Site Quickly
    • How to Quickly Build a Blog Site
    • Quick Launch via Login-Free Deployment in WorkBuddy
  • Migration Guides
    • Migrating from Vercel to EdgeOne Makers
    • Migrating from Cloudflare Pages to EdgeOne Makers
    • Migrating from Netlify to EdgeOne Makers
  • Troubleshooting
  • FAQs
  • Limits
  • Pricing
  • Contact Us
  • Release Notes

Conversation Management

Agents run in an environment where they are provisioned on-demand, can be recycled at any time, and multiple requests from the same conversation may land on different instances. Storing data solely in process memory leads to three unavoidable issues: chat history disappears as soon as the frontend refreshes; when a request lands on a different instance, the model loses context from the previous round, manifesting as "amnesia"; and in scenarios like approval workflows or human-in-the-loop tasks that require "pausing and resuming later," the state is lost after instance recycling.
context.store is a built-in session management capability of Makers Agent. It enables saving and reading conversation history with zero configuration and provides native adapters for the Claude, OpenAI, LangGraph, and DeepAgents Agent frameworks.
Its core feature is cross-instance persistence: Data is stored in the platform's Blob storage and is not bound to a process. Data written during a request remains accessible. Even after the current request ends, the write instance is recycled, or a request lands on a different instance, a new request can still retrieve the data as long as it carries the same conversation_id. You do not need to manage any external database or cache yourself.
Cross-instance persistence is supported starting from EdgeOne CLI 1.6.26. Please upgrade the CLI to this version or later (npm i -g edgeone@latest).
The underlying layer is built on the platform's Blob storage. The APIs for Node and Python are fully mirrored (JavaScript camelCase, Python snake_case). The framework integration section focuses on TypeScript, with each section including an equivalent Python sample.

Using in Two Runtimes

In the code within both the agents/ and cloud-functions/ directories, store points to the same data.
Directory
Access Point
Typical Use
agents/
context.store
Primary LLM conversation path, message appending, and Checkpointer
cloud-functions/
context.agent.store
Conversation list API and message query

Common Prerequisite: Conversation Identity

All cross-instance persistence uses conversation_id as the key. You do not need to parse it yourself: the platform parses it from the request header makers-conversation-id, injects it into context.conversation_id, and echoes makers-conversation-id and makers-run-id in the response header. Simply use context.conversation_id directly. Do not construct another one from the request body. When used as a storage key, the conversation ID has a maximum length of 256 characters.

Framework Integration

context.store provides both framework-native adapters and generic APIs.
framework
Recommended Usage
Entry Point (TS)
claude-sdk
Framework-native SessionStore
context.store.claudeSessionStore()
openai-sdk
Framework-native Session
context.store.openaiSession(sessionId)
langgraph
Framework-native Checkpointer + BaseStore
context.store.langgraphCheckpointer / .langgraphStore
deepagents
Reuse LangGraph Checkpointer + BaseStore
context.store.langgraphCheckpointer / .langgraphStore
crewai
Not supported. Use the generic API for self-management.
-

Claude Agent SDK

claudeSessionStore() returns an implementation of the SessionStore protocol (append / load / listSessions / delete / listSubkeys).
// typescript
const sessionStore = context.store.claudeSessionStore()

// python
session_store = context.store.claude_session_store()
The sessionId for the Claude SDK must be a valid UUID. If your conversation_id is not guaranteed to be a UUID (for example, something like chat-2026-08 -12-abc), use claudeSessionBinding to map it to a stable UUID: if it is already a UUID, use it as is; if not, generate one and persist the mapping. This ensures the same conversation_id always maps back to the same sessionId.
TS Example:
// agents/chat/index.ts
const conversationId = context.conversation_id ?? ''
const sessionStore = context.store.claudeSessionStore()

// Maps any business ID to a stable UUID sessionId (returns it as is if it's already a UUID; otherwise, generates one and persists it).
const sessionId = await context.store.claudeSessionBinding(conversationId)

// Checks if this sessionId has been persisted before: if yes, resumes the session; if not, treats it as a new session.
// The `dir` parameter cannot be omitted. The blob key for SessionStore is derived from the project directory. If `dir` is missing, the data can never be retrieved.
const info = await getSessionInfo(sessionId, { dir: process.cwd(), sessionStore })

const options: Record<string, any> = { model, systemPrompt, sessionStore }
if (info) {
options.resume = sessionId // Resumes an existing session
} else {
options.sessionId = sessionId // Creates a new session
}

const q = query({ prompt: message, options })
Python example:
session_store = context.store.claude_session_store()
session_id = await context.store.claude_session_binding(conversation_id)
# Similarly, when calling `getSessionInfo`, determine whether to resume or create a new session. Then, include `session_store` and either `resume` or `session_id` in the options.
We provide sample code for reference: Node, Python

OpenAI Agents SDK

openaiSession(sessionId, { maxItems }) returns an implementation of the Session protocol from the OpenAI Agents SDK (getItems / addItems / popItem / clearSession).
// openaiSession automatically resumes sessions based on the conversation id.
// typescript
const session = context.store.openaiSession(context.conversation_id)

// python
session = context.store.openai_session(context.conversation_id)
Resuming from a breakpoint (approval flow / human-in-the-loop) requires the additional use of store.state. The openaiSession above only persists conversation context; **it does not persist the RunState at the point of interruption**. Therefore, when a tool requires manual approval and the run() is interrupted midway, you must serialize the RunState and store it into context.store.state. In the next round, read it back, restore it, and then run() again:
// agents/hitl/index.ts
import { RunState, run } from '@openai/agents'
const RUN_STATE_KEY = 'openai.run-state'

// — First round: Start the run. If it is interrupted, store the RunState into state. —
const result = await run(agent, message, { signal })
if (result.state.getInterruptions().length > 0) {
await context.store.state.set(RUN_STATE_KEY, result.state.toString()) // Key: Store the RunState
return json({ status: 'awaiting_approval' })
}
await context.store.state.delete(RUN_STATE_KEY) // No interruption, run completed, clean up

// — Next round: Bring in the approval/rejection, read back the RunState to restore it, and resume the run. —
const stored = await context.store.state.get<string>(RUN_STATE_KEY)
const state = await RunState.fromString(agent, stored) // Restore the interrupted state
const [approval] = state.getInterruptions()
body.approved ? state.approve(approval) : state.reject(approval)
const resumed = await run(agent, state, { signal }) // Resume the run from the breakpoint
We provide sample code for reference: Node, Python

LangGraph

langgraphCheckpointer implements BaseCheckpointSaver (getTuple / list / put / putWrites). langgraphStore implements BaseStore (get / put / search / listNamespaces / batch). Semantic search is temporarily supported by the search method of BaseStore.
// typescript
const checkpointer = context.store.langgraphCheckpointer
const store = context.store.langgraphStore

// python
checkpointer = context.store.langgraph_checkpointer
store = context.store.langgraph_store

DeepAgents

DeepAgents is built on LangGraph and directly reuses the two adapters: langgraphCheckpointer + langgraphStore.
// typescript
const checkpointer = context.store.langgraphCheckpointer
const store = context.store.langgraphStore

// python
checkpointer = context.store.langgraph_checkpointer
store = context.store.langgraph_store

CrewAI

CrewAI's built-in Memory has a strong dependency on a vector database (default: LanceDB + embedder). A vector layer has not yet been implemented for context.store. You can manage conversation history using the generic API of context.store. Core capabilities such as multi-agent orchestration, task chaining, and tool invocation remain completely unaffected.
To restore a session across instances, serialize the framework's session state into JSON and store it at the end of each round. At the start of the next round, read it back first to restore the state. As long as the state can be expressed as a JSON-serializable object, the same cross-instance multi-turn memory and checkpoint resumption can be achieved. A typical implementation is an approval flow (human-in-the-loop). When a tool invocation requires manual approval, store the runtime state into state and return "Awaiting Approval". Next time, with the same conversation_id (approved or rejected), read back the state and resume the run from the checkpoint. Delete the state after the run completes. The serialized state always remains only on the server side.

General APIs

Method Overview

All methods are attached to context.store. The Node side uses object destructuring for parameters (camelCase), while the Python side uses keyword arguments (snake_case). Their semantics are identical.
Node Method
Python Method
Description
appendMessage
append_message
Appends a message; automatically creates a conversation if it does not exist.
getMessages
get_messages
Retrieves a list of messages and supports cursor-based pagination.
updateMessage
update_message
Overwrites a specified message.
deleteMessage
delete_message
Deletes a single message.
clearMessages
clear_messages
Clears messages but retains conversation metadata.
getConversation
get_conversation
Retrieves conversation metadata.
listConversations
list_conversations
Lists conversations in descending order of lastMessageAt.
updateConversation
update_conversation
Updates conversation metadata with a shallow merge.
deleteConversation
delete_conversation
Deletes the entire conversation (irrecoverable).
toAnthropicMessages
to_anthropic_messages
Converts a list of messages to the Anthropic Messages format.
toOpenAIInput
to_openai_input
Converts a list of messages to the OpenAI Chat Completions format.

appendMessage / append_message

Append a message to the specified conversation. If the conversation does not exist, it is automatically created, and a user index is established as needed.
Parameter
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
Business-side conversation ID, length ≤ 256 bytes
role
'user' | 'assistant' | 'system' | 'tool'
Yes
Message role
content
string | string[] | object
Yes
Message body, supporting plain text / string arrays / multimodal dict, with a serialized size ≤ 50 MB.
metadata
Record<string, any>
No
Business-defined fields (such as number of tokens, tool_call, source tags, and so on)
userId / user_id
string
No
Associated user. After being passed in, it is written to the user index to facilitate listing conversations by user.
Return Value
The messageId / message_id of the new message (in the format msg_xxx).
TS Example:
const messageId = await context.store.appendMessage({
conversationId: context.conversation_id,
role: 'user',
content: context.request.body.message,
userId: context.request.body.userId,
metadata: { source: 'web' },
})
Python example:
message_id = await context.store.append_message(
conversation_id=context.conversation_id,
role="user",
content=context.request.body["message"],
user_id=context.request.body.get("user_id"),
metadata={"source": "web"},
)

getMessages / get_messages

Retrieve the message list for a specified conversation, supporting cursor-based pagination. If the conversation does not exist, no exception is thrown and an empty list is returned. By default, the list is sorted in chronological order (order='asc', earliest first) to facilitate direct prompt assembly.
Parameter
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
Conversation ID
limit
number
No
Number of items per page, default 20, range [1, 100].
order
'asc' | 'desc'
No
Sorting direction, default 'asc' (earliest first).
after
string
No
A cursor that fetches messages after the specified messageId; mutually exclusive with before.
before
string
No
A cursor that fetches messages before the specified messageId; mutually exclusive with after.
Return Value
list[Message] A message array. An empty array [] is returned if the conversation does not exist.
TS Example:
const messages = await context.store.getMessages({
conversationId: context.conversation_id,
limit: 50,
})
const reply = await openai.chat.completions.create({
model: 'gpt-4o',
messages: context.store.toOpenAIInput(messages),
})
Python example:
messages = await context.store.get_messages(
conversation_id=context.conversation_id,
limit=50,
)
reply = await openai_client.chat.completions.create(
model="gpt-4o",
messages=context.store.to_openai_input(messages),
)

updateMessage / update_message

Overwrite a message. Only the fields you provide are overwritten, while fields not provided retain their original values. The updatedAt / updated_at timestamps are automatically refreshed.
Parameter
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
Conversation ID
messageId / message_id
string
Yes
Target message ID
content
string | string[] | object
No
New content; retains the original value if not provided.
metadata
Record<string, any>
No
Overwrites the metadata entirely (not merged); retains the original value if not provided.
Return Value
Message — The complete, updated message object.
TS Example:
const updated = await context.store.updateMessage({
conversationId: context.conversation_id,
messageId: 'msg_abc123',
content: 'corrected answer',
metadata: { edited: true },
})
Python example:
updated = await context.store.update_message(
conversation_id=context.conversation_id,
message_id="msg_abc123",
content="corrected answer",
metadata={"edited": True},
)

deleteMessage / delete_message

Delete a single message.

Parameter
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
Conversation ID
messageId / message_id
string
Yes
Target message ID
TS Example:
await context.store.deleteMessage({
conversationId: context.conversation_id,
messageId: 'msg_abc123',
})
Python example:
await context.store.delete_message(
conversation_id=context.conversation_id,
message_id="msg_abc123",
)

clearMessages / clear_messages

Clear all messages in the conversation, but retain the ConversationMeta. To delete it completely, use deleteConversation.
Parameter
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
Conversation ID
TS Example:
await context.store.clearMessages({ conversationId: context.conversation_id })
Python example:
await context.store.clear_messages(conversation_id=context.conversation_id)

getConversation / get_conversation

Obtain conversation metadata.
Parameter
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
Conversation ID
Return Value
ConversationMeta Contains fields such as conversationId / createdAt / lastMessageAt / messageCount / metadata.
TS Example:
const meta = await context.store.getConversation({
conversationId: context.conversation_id,
})
console.log(meta.messageCount, meta.metadata?.title)
Python example:
meta = await context.store.get_conversation(
conversation_id=context.conversation_id,
)
print(meta.message_count, (meta.metadata or {}).get("title"))

listConversations / list_conversations

List conversations, sorted by lastMessageAt, with support for cursor-based pagination and user-based filtering.

Parameter
Parameter
Type
Required
Description
limit
number
No
Number of items per page, default 20, range [1, 100].
order
'asc' | 'desc'
No
Sorting direction, default 'desc' (latest first).
after
string
No
A cursor that passes the nextCursor returned from the previous page.
before
string
No
A cursor that passes the previousCursor returned from the previous page.
userId / user_id
string
No
Lists only the conversations under the specified user (hits the user index).
Return Value
ListConversationsResult { items, nextCursor, previousCursor }.

TS Example:
const { items, nextCursor } = await context.store.listConversations({
userId: 'u_123',
limit: 20,
})
Python example:
result = await context.store.list_conversations(user_id="u_123", limit=20)
items, next_cursor = result.items, result.next_cursor

updateConversation / update_conversation

Shallow merge metadata: Identical keys are overwritten, while different keys are retained.
Parameter
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
Conversation ID
metadata
Record<string, any>
Yes
Fields to be merged; the key is deleted when the value is null / None.
Return Value
ConversationMeta The merged conversation metadata.
TS Example:
await context.store.updateConversation({
conversationId: context.conversation_id,
metadata: { title: 'Product Inquiry', tag: null }, // Sets the title and removes the tag.
})
Python example:
await context.store.update_conversation(
conversation_id=context.conversation_id,
metadata={"title": "Product Inquiry", "tag": None},
)

deleteConversation / delete_conversation

Delete the entire conversation and synchronously clean up the message index, conversation metadata, and global conversation index. This action is irreversible.
Parameter:
Parameter
Type
Required
Description
conversationId / conversation_id
string
Yes
Conversation ID
TS Example:
await context.store.deleteConversation({
conversationId: context.conversation_id,
})
Python example:
await context.store.delete_conversation(
conversation_id=context.conversation_id,
)

toAnthropicMessages / to_anthropic_messages

Convert the message list returned by getMessages into the format of the messages field for the Anthropic Messages API.
Parameter
Parameter
Type
Required
Description
messages
Message[]
Yes
Return result of getMessages / get_messages
Return Value
Array<{ role: string; content: unknown }> — This can be directly used as the input parameter for anthropic.messages.create({ messages }).
TS Example:
const history = await context.store.getMessages({
conversationId: context.conversation_id,
})
const resp = await anthropic.messages.create({
model: 'claude-sonnet-4',
max_tokens: 1024,
messages: context.store.toAnthropicMessages(history),
})
Python example:
history = await context.store.get_messages(
conversation_id=context.conversation_id,
)
resp = await anthropic_client.messages.create(
model="claude-sonnet-4",
max_tokens=1024,
messages=context.store.to_anthropic_messages(history),
)

toOpenAIInput / to_openai_input

Convert the message list returned by getMessages into the format of the messages field for the OpenAI Chat Completions API. Retain role values that belong to user / assistant / system / tool, and pass through the content field unchanged.
Parameter
Parameter
Type
Required
Description
messages
Message[]
Yes
Return result of getMessages / get_messages
Return Value
Array<{ role: string, content: any }> — This can be directly used as the input parameter for openai.chat.completions.create({ messages }).
TS Example:
const history = await context.store.getMessages({
conversationId: context.conversation_id,
})
const resp = await openai.chat.completions.create({
model: 'gpt-4o',
messages: context.store.toOpenAIInput(history),
})
Python example:
history = await context.store.get_messages(
conversation_id=context.conversation_id,
)
resp = await openai_client.chat.completions.create(
model="gpt-4o",
messages=context.store.to_openai_input(history),
)

state — General State Storage

The previous methods all revolve around "messages". context.store.state is another type of capability: a conversation-isolated JSON key-value store where you decide what to store. It is suitable for any framework, particularly those without native adapters (such as CrewAI), and for scenarios requiring storage of business-custom states (step counts, temporary variables, serialized framework runtime states).
The conversationId is automatically bound to the current conversation. You do not need to pass it in method calls, and writes are isolated by the conversationId namespace. Like message history and session context, values in state are also persisted across instances — even if you switch instances, reading the same conversationId will still retrieve them.
Node Method
Python Method
Description
state.get(key)
state.get(key)
Reads; returns null / None when the key does not exist.
state.set(key, value)
state.set(key, value)
Writes; the value must be JSON-serializable.
state.delete(key)
state.delete(key)
Deletes the specified key.
All three methods are asynchronous.
Parameters and Constraints
Item
Description
key
String, 1–256 characters in length
value
Must be JSON-serializable: null / string / boolean / finite number / plain object / array. Functions, circular references, NaN / Infinity are rejected.
TS Example:
// Request start: read back the state from the previous round (or null if none exists)
const saved = await context.store.state.get<MyState>('session')

// ... Run a conversation round ...

// Request end: save the latest state back.
await context.store.state.set('session', latestState)
Python example:
saved = await context.store.state.get("session")
# ... Run a round ...
await context.store.state.set("session", latest_state)
General Approach: Implementing Multi-turn Memory / Checkpoint Resumption with Other Frameworks. When no native adapter is available, the idea is to serialize the framework's session state into JSON and store it in state at the end of each round. At the start of the next round, read it back first to restore the state. As long as the state can be expressed as a JSON-serializable object, cross-process multi-turn memory and checkpoint resumption can be achieved without relying on any framework-specific adapters. A typical implementation is an approval flow (human-in-the-loop). When a tool invocation requires manual approval, serialize the framework's runtime state and store it in state, then return "Awaiting Approval". The next time, with the same conversationId (approved or rejected), read back the state, resume execution from the checkpoint, and delete the state after completion. The serialized state always remains only on the server side, while the frontend only sends messages and the "approve/reject" decision.

Data Structure

interface Message {
messageId: string // msg_xxx (automatically generated by appendMessage)
role: 'user' | 'assistant' | 'system' | 'tool'
content: any // string / array / object (multimodal)
createdAt: number // Timestamp in milliseconds
metadata?: Record<string, any> // Custom (e.g., token count, tool_call, etc.)
updatedAt?: number // Present only after updateMessage
}

interface ConversationMeta {
conversationId: string
createdAt: number // Timestamp in milliseconds
lastMessageAt: number // Timestamp in milliseconds
messageCount: number
metadata?: Record<string, any> // Business-defined (e.g., title, user, tags, etc.)
}

interface ListConversationsResult {
items: ConversationMeta[]
nextCursor?: string // The cursor for the next page, to be passed to the after parameter.
previousCursor?: string // The cursor for the previous page, to be passed to the before parameter.
}
The Python-side fields are message_id / conversation_id / created_at / last_message_at / message_count / next_cursor / previous_cursor, and their overall structure is consistent.

Limits and Quotas

Item
Default Value
Exceedance Action
conversation_id length
≤ 256 characters
Throws a MemoryValidationError.
Size of a single content item
≤ 50 MB (after serialization)
Throws a MemoryValidationError.
Maximum Messages per Conversation
10000
Throws a MemoryQuotaExceededError.
limit Upper Bound
100
Throws a MemoryValidationError.
limit Lower Bound
1
Throws a MemoryValidationError.
For a single content item that is excessively large (such as long documents and raw image data), it is recommended to store it in object storage and pass the URL into the message.

Conversation Summary

getMessages can retrieve a maximum of 100 messages per call. For long conversations, the recommended practice is to keep the most recent N pieces of original text + compress earlier content into a summary, then assemble the prompt from the Store with each request. The Store itself does not call the LLM or generate summaries; it only provides the JSON container ConversationMeta.metadata.

Responsibility Division

Responsible Party
Task/Responsibility
Store
Provide the metadata JSON field + shallow merge writes. Define two keys: summary (summary text) and summarizedUntil (the messageId up to which summarization has been performed).
Business side
Determine when to summarize, invoke a cost-effective model to generate the summary, and call updateConversation to write back.
summary / summarizedUntil are conventional keys, not part of the schema. The Store simply stores them as arbitrary JSON. You can rename them, provided that the business logic maintains consistency before and after the change.

Implementation Example

You can use a cheaper model for summarization—compression + preserving key facts do not require the reasoning capabilities of a primary model. None of the four requirements in the prompt can be omitted; otherwise, issues such as divergent summaries, inclusion of casual greetings, language inconsistencies, and increasingly lengthy summaries may occur.
async function summarizeWithLLM(previousSummary, newMessages) {
const transcript = newMessages
.filter(m => m.role === 'user' || m.role === 'assistant')
.map(m => `${m.role}: ${
typeof m.content === 'string' ? m.content : JSON.stringify(m.content)
}`)
.join('\n')
const prompt = previousSummary
? `Below are the [Existing Summary] and [New Dialogue] of a conversation. Please merge them into a new summary.
Requirements:
- Retain: key facts, user preferences, incomplete tasks, and important contextual settings.
- Delete: casual greetings, acknowledgments of receipt, duplicate content, and tool invocation details.
- Write in the same language as the most recent conversation.
- Keep it within 500 words.

[Existing Summary]
${previousSummary}

[New Dialogue]
${transcript}

[New Summary]`
: `Please summarize the following conversation into a summary.
Requirements:
- Retain: key facts, user preferences, incomplete tasks, and important contextual settings.
- Delete: casual greetings, acknowledgments of receipt, duplicate content, and tool invocation details.
- Write in the same language as the conversation.
- Keep it within 500 words.

[Dialogue]
${transcript}
[Summary]`
const { text } = await generateText({
model: openai('gpt-4o-mini'),
prompt,
maxTokens: 800,
})
return text.trim()
}

Difference Between Message Storage and Session Context Storage

context.store provides two types of independent, non-interchangeable persistence, and most conversational applications require both:
What to Store
Effect
How to Store
Message history
After the frontend page is refreshed, the chat history persists and can be re-rendered, and the sidebar can list historical sessions.
General API appendMessage / getMessages is data for pure read/write operations without invoking the model.
Conversation context
Model remembers previous conversation content (multi-turn continuous dialogue) and supports resumption after interruption.
Hand it over to the framework's native adapter (see "Cross-Instance Session Recovery"). The framework reads and writes it in the native format by itself.
The two most common misconceptions:
Only message history is recorded, without connecting to the conversation context → Records are visible in /history, but the model loses memory in each round because the context is not fed back to it.
Only the conversation context is connected, without writing message history → The model can remember, but the chat history appears blank after the frontend refreshes because the framework's session format is not designed for frontend rendering.
In a nutshell: Message history handles "visibility after refresh", while conversation context handles "model memory". Each manages its own domain, and both are persisted across instances.

ai-agent
You can ask me like
How to Get Started with EdgeOne Makers?