> ## Documentation Index
> Fetch the complete documentation index at: https://vibes-sdk.a7ul.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Messages and Chat History

> Managing conversation context with result.messages and history processors - trim, summarize, filter, and serialize messages across sessions.

Every agent run produces a list of `ModelMessage` objects. Passing these back into the next run continues the conversation, giving the model full context. History processors let you transform, trim, summarize, or filter messages before each turn - keeping context windows manageable without losing important history.

## Multi-turn conversations

```mermaid theme={null}
sequenceDiagram
    participant App
    participant Agent
    participant Model

    App->>Agent: run first message
    Agent->>Model: send message
    Model-->>Agent: response
    Agent-->>App: Result with full history

    App->>Agent: run follow-up with history
    Agent->>Model: send full conversation
    Model-->>Agent: response with context
    Agent-->>App: Result with updated history
```

Use `result.messages` as the `messageHistory` for the next run:

```typescript theme={null}
import { Agent } from "@vibesjs/sdk";
import { anthropic } from "@ai-sdk/anthropic";

const agent = new Agent({
  model: anthropic("claude-sonnet-4-6"),
  systemPrompt: "You are a helpful assistant.",
});

const first = await agent.run("My name is Alice.");
const second = await agent.run("What is my name?", {
  messageHistory: first.messages,  // continue the conversation
});

console.log(second.output);       // "Your name is Alice."
console.log(second.newMessages);  // only messages added in this run
```

`result.messages` contains the **full** conversation history (including prior turns). `result.newMessages` contains only the messages added during this specific run - useful for storing incremental updates.

## Message serialization

To persist conversation history across sessions, serialize messages to JSON and restore them later.

```typescript theme={null}
import { serializeMessages, deserializeMessages } from "@vibesjs/sdk";

// After a run - store to DB or file
const json = serializeMessages(result.messages);
await db.save("session-123", json);

// On next session - restore for continuation
const stored = await db.load("session-123");
const messages = deserializeMessages(stored);

const next = await agent.run("What did we discuss?", {
  messageHistory: messages,
});
```

`serializeMessages` encodes `ModelMessage[]` to a JSON string. `deserializeMessages` is the inverse: it parses and validates the JSON, returning a typed `ModelMessage[]`.

## History processors

`historyProcessors` run before each turn and receive the accumulated message history. They return a (possibly modified) message list that is sent to the model. Use them to keep context windows affordable without losing important history.

```typescript theme={null}
const agent = new Agent({
  model,
  historyProcessors: [trimHistoryProcessor(20)],
});
```

Multiple processors are applied in order, each receiving the output of the previous.

### trimHistoryProcessor

Keep the last N messages. Simple and fast - good for short-context workflows.

```typescript theme={null}
import { trimHistoryProcessor } from "@vibesjs/sdk";

const agent = new Agent({
  model,
  historyProcessors: [trimHistoryProcessor(20)],  // keep last 20 messages
});
```

### tokenTrimHistoryProcessor

Trim messages to fit within a token budget. Removes older messages first until the history fits.

```typescript theme={null}
import { tokenTrimHistoryProcessor } from "@vibesjs/sdk";

const agent = new Agent({
  model,
  historyProcessors: [tokenTrimHistoryProcessor(4000)],  // max 4000 tokens
});
```

### summarizeHistoryProcessor

Summarize messages that exceed a threshold, replacing them with a condensed summary message. Preserves semantic content while reducing token count.

```typescript theme={null}
import { summarizeHistoryProcessor } from "@vibesjs/sdk";

const agent = new Agent({
  model,
  historyProcessors: [
    summarizeHistoryProcessor(model, {
      maxMessages: 10,           // default: 20 - summarize when history exceeds this
      summarizePrompt: "Summarize the conversation so far:", // optional custom prompt
    }),
  ],
});
```

The second argument accepts `{ maxMessages?: number; summarizePrompt?: string }`. When the non-system message count exceeds `maxMessages`, the older portion is summarized and replaced with a single summary message. The most recent `floor(maxMessages / 2)` messages are always kept verbatim. System messages are always preserved.

### privacyFilterProcessor

Redact sensitive content before messages are sent to the model. Supports regex-based redaction and field-path-based removal.

```typescript theme={null}
import { privacyFilterProcessor } from "@vibesjs/sdk";

const agent = new Agent({
  model,
  historyProcessors: [
    privacyFilterProcessor([
      // RegexPrivacyRule - replace pattern matches with a placeholder
      { pattern: /\d{4}-\d{4}-\d{4}-\d{4}/g, replacement: "[CARD]" },
      // FieldPrivacyRule - remove a specific field from tool messages
      { messageType: "tool", fieldPath: "content.0.result.ssn" },
    ]),
  ],
});
```

The two rule types:

| Rule type          | Shape                                        | When to use                                                   |
| ------------------ | -------------------------------------------- | ------------------------------------------------------------- |
| `RegexPrivacyRule` | `{ pattern: RegExp, replacement?: string }`  | Redact patterns anywhere in text (credit cards, emails, etc.) |
| `FieldPrivacyRule` | `{ messageType: string, fieldPath: string }` | Remove a specific structured field from tool call results     |

<Warning>
  Do not use `{ type: "regex", redactValue: ... }` - that shape is incorrect. The actual `PrivacyRule` union uses `pattern` for regex rules with no `type` key.
</Warning>

## Custom history processors

A history processor is any function that takes `(messages: ModelMessage[], ctx: RunContext<TDeps>)` and returns a `ModelMessage[]`.

```typescript theme={null}
import type { HistoryProcessor } from "@vibesjs/sdk";

// Keep only user and assistant messages - drop tool calls
const noTools: HistoryProcessor = (messages, _ctx) =>
  messages.filter((m) => m.role === "user" || m.role === "assistant");

const agent = new Agent({
  model,
  historyProcessors: [noTools],
});
```

Custom processors compose with built-in ones - pass them in the same array.

***

<CardGroup cols={2}>
  <Card title="Streaming" icon="bolt" href="/concepts/streaming">
    Real-time token and event streaming
  </Card>

  <Card title="Agents" icon="robot" href="/concepts/agents">
    Agent class, run methods, and options
  </Card>
</CardGroup>
