Threads and Messages
Threads are conversation sessions in Flapjack. Messages are individual turns streamed via SSE. Learn the conversation lifecycle.
A thread is a conversation session between a user and an agent. A message is a single turn within that thread.
Thread Lifecycle
Create Thread → Send Message → Receive Stream → Send Another → ...
- Create a thread for a specific agent
- Send messages to the thread — each triggers an agent response
- Receive responses as SSE streams with incremental tokens
- The thread maintains full conversation history automatically
Thread Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier (UUID) |
org_id | string | Organization that owns this thread |
agent_id | string | The agent this thread belongs to |
title | string | null | Optional thread title |
active_profile | string | null | Active tool profile (null = use agent default) |
created_at | string | ISO 8601 timestamp |
TypeScript Type
type Thread = {
id: string;
org_id: string;
agent_id: string;
title: string | null;
active_profile?: string | null;
created_at: string;
};
Creating a Thread
SDK
const thread = await client.createThread('agent-id');
console.log(thread.id); // Use this to send messages
📋 Copy as prompt
Create a new Flapjack thread for my agent using
client.createThread(agentId), then log the thread ID.
API
curl -X POST https://api.flapjack.dev/api/threads \
-H "Authorization: Bearer fj_live_..." \
-H "Content-Type: application/json" \
-d '{"agentId": "your-agent-id"}'
Sending Messages
Messages are sent to a thread and the response is streamed back via SSE.
SDK
for await (const event of client.sendMessage(thread.id, 'What is Flapjack?')) {
if (event.type === 'token') process.stdout.write(event.delta);
if (event.type === 'done') console.log('\n', event.content);
}
📋 Copy as prompt
Send a message to a Flapjack thread using
client.sendMessage(threadId, message)and stream the response, printing each token as it arrives.
API
curl -N -X POST https://api.flapjack.dev/api/threads/{threadId}/messages \
-H "Authorization: Bearer fj_live_..." \
-H "Content-Type: application/json" \
-d '{"content": "What is Flapjack?"}'
Message Roles
Messages in a thread have one of these roles:
| Role | Description |
|---|---|
user | Message sent by the user |
assistant | Response from the agent |
tool | Result of a tool execution |
system | System-level message |
Message Type
The SDK exposes a simplified message type for the useChat hook:
// SDK simplified type (useChat hook)
type Message = {
role: 'user' | 'assistant';
content: string;
systemMessage?: SystemMessageMeta;
};
type SystemMessageMeta = {
icon: string; // 'check' | 'tool' | 'info' | 'error' or any emoji/character
label: string; // Short text shown next to the icon
};
The full API/database message model includes additional roles (tool, system) and fields like tool_name, tool_call, and tool_result_ref.
System User Messages
Some user messages represent system activity rather than typed user input — for example, approving a plan, confirming a tool execution, or acknowledging an MCP event. These are regular role: 'user' messages with a systemMessage metadata field that tells the UI to render them as a compact, centered status indicator (icon + label pill) instead of a chat bubble.
Built-in icon keys:
| Key | Glyph | Use case |
|---|---|---|
check | ✓ | Plan approved, action confirmed |
tool | 🔧 | Tool / MCP activity |
info | ℹ | General information |
error | ✕ | Error / rejection |
Any other string is rendered as-is (e.g. "🚀" or "★").
// Inject a system message via the useChat hook
const { addSystemMessage } = useChat(agentId);
addSystemMessage(
{ icon: 'check', label: 'Plan approved' },
{ content: 'Approved. Please proceed with the plan.' },
);
See SDK: React Hooks for full addSystemMessage API.
Conversation History
Flapjack automatically maintains the full conversation history for each thread. When you send a new message, the agent receives all prior messages in the thread as context. You don't need to manage history yourself.
Listing Threads
Retrieve a user's past conversation threads for an agent:
const { threads, nextCursor } = await client.listThreads('agent-id');
Threads are returned newest-first with cursor-based pagination. For JWT auth, only the current user's threads are returned. For API key auth, all org threads are returned.
See SDK: Client — listThreads and API: Threads — List Threads.
Retrieving Messages
Fetch the message history for a specific thread:
const { messages, total } = await client.getMessages('thread-id');
Returns user and assistant messages in chronological order with offset-based pagination.
See SDK: Client — getMessages and API: Threads — Get Messages.
Resuming a Thread
In the React SDK, pass a threadId to the useChat hook to resume an existing conversation:
const { messages, sendMessage } = useChat(agentId, { threadId: 'existing-thread-id' });
Messages are loaded automatically on mount. Use loadThread(id) to switch threads at runtime.
See SDK: React — Resuming a Thread.
Stopping a Response
To stop an active response mid-stream:
curl -X POST https://api.flapjack.dev/api/threads/{threadId}/stop \
-H "Authorization: Bearer fj_live_..."
Next Steps
- Streaming — SSE event types in detail
- Tools — what happens when an agent calls a tool
- API: Threads — full endpoint reference