Skip to content

Commit 14e751e

Browse files
BenTaylorDevclaude
andcommitted
docs(threads): align pagination API names and document lock tuning options
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent cc260e3 commit 14e751e

5 files changed

Lines changed: 57 additions & 28 deletions

File tree

docs/content/docs/(root)/threads.mdx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,23 @@ CopilotKit threads enable persistent, resumable multi-turn conversations. The `u
4242
// Thread names are auto-generated by default.
4343
// Set to false to disable:
4444
// generateThreadNames: false,
45+
46+
// Optional: tune thread lock behavior
47+
// lockTtlSeconds: 20, // Lock TTL (default 20s, max 3600s)
48+
// lockHeartbeatIntervalSeconds: 15, // Heartbeat interval (default 15s, max 3000s)
49+
// lockKeyPrefix: "my-app", // Custom Redis key prefix for the lock
4550
});
4651
```
4752

4853
If you're using Copilot Cloud, thread storage is handled automatically. For self-hosted Enterprise, configure your database connection per the Enterprise setup guide.
54+
55+
**Thread lock options:** When an agent run starts, the runtime acquires a lock on the thread to prevent concurrent runs. You can tune this behavior:
56+
57+
| Option | Default | Max | Description |
58+
|--------|---------|-----|-------------|
59+
| `lockTtlSeconds` | `20` | `3600` (1 hour) | How long the lock is held before it expires automatically. |
60+
| `lockHeartbeatIntervalSeconds` | `15` | `3000` (50 min) | How often the runtime renews the lock during a run. |
61+
| `lockKeyPrefix` ||| Custom Redis key prefix for the thread lock. Useful when multiple apps share a Redis instance. |
4962
</Step>
5063

5164
<Step>
@@ -122,21 +135,21 @@ CopilotKit threads enable persistent, resumable multi-turn conversations. The `u
122135
```tsx title="ThreadSidebar.tsx"
123136
const {
124137
threads,
125-
hasNextPage,
126-
isFetchingNextPage,
127-
fetchNextPage,
138+
hasMoreThreads,
139+
isFetchingMoreThreads,
140+
fetchMoreThreads,
128141
} = useThreads({
129142
agentId: "my-agent",
130143
limit: 20, // [!code highlight]
131144
});
132145

133146
// In your JSX:
134-
{hasNextPage && (
147+
{hasMoreThreads && (
135148
<button
136-
onClick={fetchNextPage}
137-
disabled={isFetchingNextPage}
149+
onClick={fetchMoreThreads}
150+
disabled={isFetchingMoreThreads}
138151
>
139-
{isFetchingNextPage ? "Loading..." : "Load more"}
152+
{isFetchingMoreThreads ? "Loading..." : "Load more"}
140153
</button>
141154
)}
142155
```

docs/content/docs/learn/threads.mdx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ From a developer's perspective, threads involve three things:
2323

2424
| What you use | What it does |
2525
|-------------|-------------|
26-
| `useThreads` hook | Lists, renames, archives, and deletes threads. Stays in sync across tabs and devices via WebSocket. |
26+
| `useThreads` hook | Lists, renames, archives, and deletes threads. Pagination via `hasMoreThreads` / `fetchMoreThreads`. Stays in sync across tabs and devices via WebSocket. |
2727
| `CopilotChat` with `threadId` | Connects to a specific thread, loads its history, and streams new events in realtime. |
2828
| `CopilotRuntime` | Server-side layer that executes agents, stores thread data on the Intelligence Platform, and relays events to connected clients. |
2929

@@ -114,6 +114,16 @@ If the WebSocket connection drops (network change, server restart, laptop sleep)
114114

115115
If a thread already has an active run and another client tries to start a new run on the same thread, the request is rejected with a **409 Conflict**. This prevents two agent runs from interleaving events on the same thread. The existing run must complete or be stopped before a new one can begin.
116116

117+
The runtime acquires a Redis-backed lock on the thread for the duration of each run. You can tune this behavior on the runtime:
118+
119+
| Option | Default | Max | Description |
120+
|--------|---------|-----|-------------|
121+
| `lockTtlSeconds` | `20` | `3600` (1 hour) | How long the lock is held before it expires automatically. |
122+
| `lockHeartbeatIntervalSeconds` | `15` | `3000` (50 min) | How often the runtime renews the lock during a run. The heartbeat always runs — you only need to adjust the interval. |
123+
| `lockKeyPrefix` ||| Custom Redis key prefix for the thread lock. Useful when multiple apps share a Redis instance. |
124+
125+
If a run completes normally, the lock is released immediately. The TTL is a safety net for cases where the runtime crashes without releasing the lock.
126+
117127
## Design decisions
118128

119129
### Why event replay instead of message snapshots?

docs/content/docs/learn/tutorials/multi-conversation-chat.mdx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,9 @@ A chat application with a thread sidebar — similar to ChatGPT or Claude's conv
228228
const {
229229
threads,
230230
isLoading,
231-
hasNextPage, // [!code highlight]
232-
isFetchingNextPage, // [!code highlight]
233-
fetchNextPage, // [!code highlight]
231+
hasMoreThreads, // [!code highlight]
232+
isFetchingMoreThreads, // [!code highlight]
233+
fetchMoreThreads, // [!code highlight]
234234
renameThread,
235235
archiveThread,
236236
} = useThreads({
@@ -239,13 +239,13 @@ A chat application with a thread sidebar — similar to ChatGPT or Claude's conv
239239
});
240240

241241
// At the bottom of the thread list:
242-
{hasNextPage && (
242+
{hasMoreThreads && (
243243
<button
244244
className="m-3 p-2 text-sm text-gray-500 hover:text-gray-700"
245-
onClick={fetchNextPage}
246-
disabled={isFetchingNextPage}
245+
onClick={fetchMoreThreads}
246+
disabled={isFetchingMoreThreads}
247247
>
248-
{isFetchingNextPage ? "Loading..." : "Load older conversations"}
248+
{isFetchingMoreThreads ? "Loading..." : "Load older conversations"}
249249
</button>
250250
)}
251251
```

docs/content/docs/reference/v2/hooks/useThreads.mdx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function useThreads(input: UseThreadsInput): UseThreadsResult
3232
</PropertyReference>
3333

3434
<PropertyReference name="limit" type="number" default="undefined">
35-
Maximum number of threads to fetch per page. When set, enables cursor-based pagination via `fetchNextPage()` and `hasNextPage`.
35+
Maximum number of threads to fetch per page. When set, enables cursor-based pagination via `fetchMoreThreads()` and `hasMoreThreads`.
3636
</PropertyReference>
3737
</PropertyReference>
3838

@@ -45,6 +45,7 @@ function useThreads(input: UseThreadsInput): UseThreadsResult
4545
<PropertyReference name="threads" type="Thread[]">
4646
Array of threads for the current user and agent, sorted by most recently updated first. Each `Thread` contains:
4747
- `id: string` — unique thread identifier
48+
- `agentId: string` — the agent this thread belongs to
4849
- `name: string | null` — thread name (auto-generated by the LLM on first run, or set manually via `renameThread`)
4950
- `archived: boolean` — whether the thread is archived
5051
- `createdAt: string` — ISO 8601 timestamp
@@ -59,18 +60,18 @@ function useThreads(input: UseThreadsInput): UseThreadsResult
5960
The most recent error from fetching or mutating threads, or `null` if no error has occurred.
6061
</PropertyReference>
6162

62-
<PropertyReference name="hasNextPage" type="boolean">
63+
<PropertyReference name="hasMoreThreads" type="boolean">
6364
`true` when more threads are available beyond the current page. Only meaningful when `limit` is set.
6465
</PropertyReference>
6566

66-
<PropertyReference name="isFetchingNextPage" type="boolean">
67-
`true` while the next page of threads is being fetched.
67+
<PropertyReference name="isFetchingMoreThreads" type="boolean">
68+
`true` while additional threads are being fetched.
6869
</PropertyReference>
6970

7071
### Methods
7172

72-
<PropertyReference name="fetchNextPage" type="() => void">
73-
Fetch the next page of threads. No-op if `hasNextPage` is `false` or a fetch is already in progress.
73+
<PropertyReference name="fetchMoreThreads" type="() => void">
74+
Fetch the next page of threads. No-op if `hasMoreThreads` is `false` or a fetch is already in progress.
7475
</PropertyReference>
7576

7677
<PropertyReference name="renameThread" type="(threadId: string, name: string) => Promise<void>">

docs/snippets/shared/threads/threads.mdx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ CopilotKit threads enable persistent, resumable multi-turn conversations. The `u
3535
// Thread names are auto-generated by default.
3636
// Set to false to disable:
3737
// generateThreadNames: false,
38+
39+
// Optional: tune thread lock behavior
40+
// lockTtlSeconds: 20, // Lock TTL (default 20s, max 3600s)
41+
// lockHeartbeatIntervalSeconds: 15, // Heartbeat interval (default 15s, max 3000s)
42+
// lockKeyPrefix: "my-app", // Custom Redis key prefix for the lock
3843
});
3944
```
4045

@@ -115,21 +120,21 @@ CopilotKit threads enable persistent, resumable multi-turn conversations. The `u
115120
```tsx title="ThreadSidebar.tsx"
116121
const {
117122
threads,
118-
hasNextPage,
119-
isFetchingNextPage,
120-
fetchNextPage,
123+
hasMoreThreads,
124+
isFetchingMoreThreads,
125+
fetchMoreThreads,
121126
} = useThreads({
122127
agentId: "my-agent",
123128
limit: 20, // [!code highlight]
124129
});
125130

126131
// In your JSX:
127-
{hasNextPage && (
132+
{hasMoreThreads && (
128133
<button
129-
onClick={fetchNextPage}
130-
disabled={isFetchingNextPage}
134+
onClick={fetchMoreThreads}
135+
disabled={isFetchingMoreThreads}
131136
>
132-
{isFetchingNextPage ? "Loading..." : "Load more"}
137+
{isFetchingMoreThreads ? "Loading..." : "Load more"}
133138
</button>
134139
)}
135140
```

0 commit comments

Comments
 (0)