Skip to content

Commit 3dc6963

Browse files
BenTaylorDevmaxkorp
authored andcommitted
fix(threads): Improve useThreads DX with clearer names and direct type hints
1 parent 418c26f commit 3dc6963

2 files changed

Lines changed: 89 additions & 15 deletions

File tree

packages/react-core/src/v2/hooks/__tests__/use-threads.test.tsx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,60 @@ describe("useThreads", () => {
383383
});
384384
});
385385

386+
it("exposes thread-scoped pagination properties", async () => {
387+
fetchMock
388+
.mockReturnValueOnce(
389+
jsonResponse({
390+
threads: sampleThreads,
391+
joinCode: "jc-1",
392+
nextCursor: "cursor-abc",
393+
}),
394+
)
395+
.mockReturnValueOnce(jsonResponse({ joinToken: "jt-1" }));
396+
397+
const { result } = renderHook(() => useThreads(defaultInput));
398+
399+
await waitFor(() => {
400+
expect(result.current.isLoading).toBe(false);
401+
});
402+
403+
expect(result.current).toHaveProperty("hasMoreThreads");
404+
expect(result.current).toHaveProperty("isFetchingMoreThreads");
405+
expect(result.current).toHaveProperty("fetchMoreThreads");
406+
expect(result.current).not.toHaveProperty("hasNextPage");
407+
expect(result.current).not.toHaveProperty("isFetchingNextPage");
408+
expect(result.current).not.toHaveProperty("fetchNextPage");
409+
410+
expect(result.current.hasMoreThreads).toBe(true);
411+
expect(result.current.isFetchingMoreThreads).toBe(false);
412+
expect(typeof result.current.fetchMoreThreads).toBe("function");
413+
});
414+
415+
it("does not expose organizationId or createdById on threads", async () => {
416+
fetchMock
417+
.mockReturnValueOnce(
418+
jsonResponse({ threads: sampleThreads, joinCode: "jc-1" }),
419+
)
420+
.mockReturnValueOnce(jsonResponse({ joinToken: "jt-1" }));
421+
422+
const { result } = renderHook(() => useThreads(defaultInput));
423+
424+
await waitFor(() => {
425+
expect(result.current.isLoading).toBe(false);
426+
});
427+
428+
for (const thread of result.current.threads) {
429+
expect(thread).not.toHaveProperty("organizationId");
430+
expect(thread).not.toHaveProperty("createdById");
431+
expect(thread).toHaveProperty("id");
432+
expect(thread).toHaveProperty("agentId");
433+
expect(thread).toHaveProperty("name");
434+
expect(thread).toHaveProperty("archived");
435+
expect(thread).toHaveProperty("createdAt");
436+
expect(thread).toHaveProperty("updatedAt");
437+
}
438+
});
439+
386440
it("tears down sockets after repeated connection failures", async () => {
387441
fetchMock
388442
.mockReturnValueOnce(

packages/react-core/src/v2/hooks/use-threads.tsx

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
ɵselectThreadsIsLoading,
77
ɵselectHasNextPage,
88
ɵselectIsFetchingNextPage,
9-
type ɵThread as CoreThread,
109
type ɵThreadRuntimeContext,
1110
type ɵThreadStore,
1211
} from "@copilotkit/core";
@@ -24,7 +23,14 @@ import {
2423
* Each thread has a unique `id`, an optional human-readable `name`, and
2524
* timestamp fields tracking creation and update times.
2625
*/
27-
export interface Thread extends CoreThread {}
26+
export interface Thread {
27+
id: string;
28+
agentId: string;
29+
name: string | null;
30+
archived: boolean;
31+
createdAt: string;
32+
updatedAt: string;
33+
}
2834

2935
/**
3036
* Configuration for the {@link useThreads} hook.
@@ -68,18 +74,18 @@ export interface UseThreadsResult {
6874
error: Error | null;
6975
/**
7076
* `true` when there are more threads available to fetch via
71-
* {@link fetchNextPage}. Only meaningful when `limit` is set.
77+
* {@link fetchMoreThreads}. Only meaningful when `limit` is set.
7278
*/
73-
hasNextPage: boolean;
79+
hasMoreThreads: boolean;
7480
/**
7581
* `true` while a subsequent page of threads is being fetched.
7682
*/
77-
isFetchingNextPage: boolean;
83+
isFetchingMoreThreads: boolean;
7884
/**
79-
* Fetch the next page of threads. No-op when {@link hasNextPage} is
80-
* `false` or a page fetch is already in progress.
85+
* Fetch the next page of threads. No-op when {@link hasMoreThreads} is
86+
* `false` or a fetch is already in progress.
8187
*/
82-
fetchNextPage: () => void;
88+
fetchMoreThreads: () => void;
8389
/**
8490
* Rename a thread on the platform.
8591
* Resolves when the server confirms the update; rejects on failure.
@@ -169,11 +175,25 @@ export function useThreads({
169175
}),
170176
);
171177

172-
const threads = useThreadStoreSelector(store, ɵselectThreads);
178+
const coreThreads = useThreadStoreSelector(store, ɵselectThreads);
179+
const threads: Thread[] = useMemo(
180+
() =>
181+
coreThreads.map(
182+
({ id, agentId, name, archived, createdAt, updatedAt }) => ({
183+
id,
184+
agentId,
185+
name,
186+
archived,
187+
createdAt,
188+
updatedAt,
189+
}),
190+
),
191+
[coreThreads],
192+
);
173193
const storeIsLoading = useThreadStoreSelector(store, ɵselectThreadsIsLoading);
174194
const storeError = useThreadStoreSelector(store, ɵselectThreadsError);
175-
const hasNextPage = useThreadStoreSelector(store, ɵselectHasNextPage);
176-
const isFetchingNextPage = useThreadStoreSelector(
195+
const hasMoreThreads = useThreadStoreSelector(store, ɵselectHasNextPage);
196+
const isFetchingMoreThreads = useThreadStoreSelector(
177197
store,
178198
ɵselectIsFetchingNextPage,
179199
);
@@ -240,15 +260,15 @@ export function useThreads({
240260
[store],
241261
);
242262

243-
const fetchNextPage = useCallback(() => store.fetchNextPage(), [store]);
263+
const fetchMoreThreads = useCallback(() => store.fetchNextPage(), [store]);
244264

245265
return {
246266
threads,
247267
isLoading,
248268
error,
249-
hasNextPage,
250-
isFetchingNextPage,
251-
fetchNextPage,
269+
hasMoreThreads,
270+
isFetchingMoreThreads,
271+
fetchMoreThreads,
252272
renameThread,
253273
archiveThread,
254274
deleteThread,

0 commit comments

Comments
 (0)