Skip to content

Commit 659e529

Browse files
committed
fix(tasks): preserve empty pagination cursors
1 parent 16d13ab commit 659e529

5 files changed

Lines changed: 26 additions & 3 deletions

File tree

packages/client/src/experimental/tasks/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ export class ExperimentalClientTasks {
210210
* @experimental
211211
*/
212212
async listTasks(cursor?: string, options?: RequestOptions): Promise<ListTasksResult> {
213-
return this._module.listTasks(cursor ? { cursor } : undefined, options);
213+
return this._module.listTasks(cursor === undefined ? undefined : { cursor }, options);
214214
}
215215

216216
/**

packages/core/src/experimental/tasks/stores/inMemory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ export class InMemoryTaskStore implements TaskStore {
197197
.map(([taskId]) => taskId);
198198

199199
let startIndex = 0;
200-
if (cursor) {
200+
if (cursor !== undefined) {
201201
const cursorIndex = filteredTaskIds.indexOf(cursor);
202202
if (cursorIndex === -1) {
203203
// Invalid cursor - throw error

packages/core/test/experimental/inMemory.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,15 @@ describe('InMemoryTaskStore', () => {
628628
await expect(store.listTasks('non-existent-cursor')).rejects.toThrow('Invalid cursor: non-existent-cursor');
629629
});
630630

631+
it('should not treat an empty string cursor as an omitted cursor', async () => {
632+
await store.createTask({}, 1, {
633+
method: 'tools/call',
634+
params: {}
635+
});
636+
637+
await expect(store.listTasks('')).rejects.toThrow('Invalid cursor: ');
638+
});
639+
631640
it('should continue from cursor correctly', async () => {
632641
// Create 5 tasks
633642
for (let i = 1; i <= 5; i++) {

packages/server/src/experimental/tasks/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ export class ExperimentalServerTasks {
281281
* @experimental
282282
*/
283283
async listTasks(cursor?: string, options?: RequestOptions): Promise<ListTasksResult> {
284-
return this._module.listTasks(cursor ? { cursor } : undefined, options);
284+
return this._module.listTasks(cursor === undefined ? undefined : { cursor }, options);
285285
}
286286

287287
/**

test/integration/test/experimental/tasks/taskListing.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,20 @@ describe('Task Listing with Pagination', () => {
9696
});
9797
});
9898

99+
it('should not treat an empty string cursor as an omitted cursor', async () => {
100+
await taskStore.createTask({}, 1, {
101+
method: 'tools/call',
102+
params: { name: 'test-tool' }
103+
});
104+
105+
await expect(client.experimental.tasks.listTasks('')).rejects.toSatisfy((error: ProtocolError) => {
106+
expect(error).toBeInstanceOf(ProtocolError);
107+
expect(error.code).toBe(ProtocolErrorCode.InvalidParams);
108+
expect(error.message).toContain('Invalid cursor');
109+
return true;
110+
});
111+
});
112+
99113
it('should ensure tasks accessible via tasks/get are also accessible via tasks/list', async () => {
100114
// Create a task
101115
const task = await taskStore.createTask({}, 1, {

0 commit comments

Comments
 (0)