v2 - RFC Extract Tasks out of protocol.ts into TaskManager (#1673)

Co-authored-by: Felix Weinberger <fweinberger@anthropic.com>
This commit is contained in:
Konstantin Konstantinov 2026-03-25 21:58:01 +02:00 • committed by GitHub
commit 462c3fc47d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 2122 additions and 1942 deletions

View file

@ -2258,10 +2258,13 @@ describe('outputSchema validation', () => {
throw new Error('Unknown tool');
});
const client = new Client({
name: 'test-client',
version: '1.0.0'
});
const client = new Client(
{
name: 'test-client',
version: '1.0.0'
},
{ capabilities: { tasks: { requests: { tools: { call: {} } } } } }
);
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
@ -2302,10 +2305,11 @@ describe('Task-based execution', () => {
tools: {
call: {}
}
}
},
taskStore: serverTaskStore
}
},
taskStore: serverTaskStore
}
}
);
@ -2342,10 +2346,13 @@ describe('Task-based execution', () => {
}
);
const client = new Client({
name: 'test-client',
version: '1.0.0'
});
const client = new Client(
{
name: 'test-client',
version: '1.0.0'
},
{ capabilities: { tasks: { requests: { tools: { call: {} } } } } }
);
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
@ -2381,10 +2388,11 @@ describe('Task-based execution', () => {
tools: {
call: {}
}
}
},
taskStore: serverTaskStore
}
},
taskStore: serverTaskStore
}
}
);
@ -2421,10 +2429,13 @@ describe('Task-based execution', () => {
}
);
const client = new Client({
name: 'test-client',
version: '1.0.0'
});
const client = new Client(
{
name: 'test-client',
version: '1.0.0'
},
{ capabilities: { tasks: { requests: { tools: { call: {} } } } } }
);
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
@ -2461,10 +2472,11 @@ describe('Task-based execution', () => {
call: {},
list: {}
}
}
},
taskStore: serverTaskStore
}
},
taskStore: serverTaskStore
}
}
);
@ -2501,10 +2513,13 @@ describe('Task-based execution', () => {
}
);
const client = new Client({
name: 'test-client',
version: '1.0.0'
});
const client = new Client(
{
name: 'test-client',
version: '1.0.0'
},
{ capabilities: { tasks: { requests: { tools: { call: {} } } } } }
);
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
@ -2545,10 +2560,11 @@ describe('Task-based execution', () => {
tools: {
call: {}
}
}
},
taskStore: serverTaskStore
}
},
taskStore: serverTaskStore
}
}
);
@ -2585,10 +2601,13 @@ describe('Task-based execution', () => {
}
);
const client = new Client({
name: 'test-client',
version: '1.0.0'
});
const client = new Client(
{
name: 'test-client',
version: '1.0.0'
},
{ capabilities: { tasks: { requests: { tools: { call: {} } } } } }
);
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
@ -2652,10 +2671,11 @@ describe('Task-based execution', () => {
elicitation: {
create: {}
}
}
},
taskStore: clientTaskStore
}
},
taskStore: clientTaskStore
}
}
);
@ -2744,10 +2764,11 @@ describe('Task-based execution', () => {
elicitation: {
create: {}
}
}
},
taskStore: clientTaskStore
}
},
taskStore: clientTaskStore
}
}
);
@ -2835,10 +2856,11 @@ describe('Task-based execution', () => {
elicitation: {
create: {}
}
}
},
taskStore: clientTaskStore
}
},
taskStore: clientTaskStore
}
}
);
@ -2925,10 +2947,11 @@ describe('Task-based execution', () => {
elicitation: {
create: {}
}
}
},
taskStore: clientTaskStore
}
},
taskStore: clientTaskStore
}
}
);
@ -3027,10 +3050,11 @@ describe('Task-based execution', () => {
tools: {
call: {}
}
}
},
taskStore: serverTaskStore
}
},
taskStore: serverTaskStore
}
}
);
@ -3152,10 +3176,11 @@ describe('Task-based execution', () => {
tools: {
call: {}
}
}
},
taskStore: serverTaskStore
}
},
taskStore: serverTaskStore
}
}
);
@ -3199,10 +3224,11 @@ describe('Task-based execution', () => {
tools: {
call: {}
}
}
},
taskStore: serverTaskStore
}
},
taskStore: serverTaskStore
}
}
);
@ -3246,10 +3272,11 @@ describe('Task-based execution', () => {
elicitation: {
create: {}
}
}
},
taskStore: clientTaskStore
}
},
taskStore: clientTaskStore
}
}
);
@ -3300,10 +3327,11 @@ test('should respect server task capabilities', async () => {
tools: {
call: {}
}
}
},
taskStore: serverTaskStore
}
},
taskStore: serverTaskStore
}
}
);
@ -3346,7 +3374,16 @@ test('should respect server task capabilities', async () => {
version: '1.0.0'
},
{
enforceStrictCapabilities: true
enforceStrictCapabilities: true,
capabilities: {
tasks: {
requests: {
tools: {
call: {}
}
}
}
}
}
);
@ -3419,7 +3456,7 @@ test('should expose requestStream() method for streaming responses', async () =>
version: '1.0.0'
},
{
capabilities: {}
capabilities: { tasks: { requests: { tools: { call: {} } } } }
}
);
@ -3481,7 +3518,7 @@ test('should expose callToolStream() method for streaming tool calls', async ()
version: '1.0.0'
},
{
capabilities: {}
capabilities: { tasks: { requests: { tools: { call: {} } } } }
}
);
@ -3559,7 +3596,7 @@ test('should validate structured output in callToolStream()', async () => {
version: '1.0.0'
},
{
capabilities: {}
capabilities: { tasks: { requests: { tools: { call: {} } } } }
}
);
@ -3637,7 +3674,7 @@ test('callToolStream() should yield error when structuredContent does not match
version: '1.0.0'
},
{
capabilities: {}
capabilities: { tasks: { requests: { tools: { call: {} } } } }
}
);
@ -3710,7 +3747,7 @@ test('callToolStream() should yield error when tool with outputSchema returns no
version: '1.0.0'
},
{
capabilities: {}
capabilities: { tasks: { requests: { tools: { call: {} } } } }
}
);
@ -3775,7 +3812,7 @@ test('callToolStream() should handle tools without outputSchema normally', async
version: '1.0.0'
},
{
capabilities: {}
capabilities: { tasks: { requests: { tools: { call: {} } } } }
}
);
@ -3870,7 +3907,7 @@ test('callToolStream() should handle complex JSON schema validation', async () =
version: '1.0.0'
},
{
capabilities: {}
capabilities: { tasks: { requests: { tools: { call: {} } } } }
}
);
@ -3949,7 +3986,7 @@ test('callToolStream() should yield error with additional properties when not al
version: '1.0.0'
},
{
capabilities: {}
capabilities: { tasks: { requests: { tools: { call: {} } } } }
}
);
@ -4023,7 +4060,7 @@ test('callToolStream() should not validate structuredContent when isError is tru
version: '1.0.0'
},
{
capabilities: {}
capabilities: { tasks: { requests: { tools: { call: {} } } } }
}
);

View file

@ -50,11 +50,11 @@ export async function createInMemoryTaskEnvironment(options?: {
tools: {
call: {}
}
}
},
taskStore,
taskMessageQueue: new InMemoryTaskMessageQueue()
}
},
taskStore,
taskMessageQueue: new InMemoryTaskMessageQueue()
}
}
);

View file

@ -1875,182 +1875,195 @@ describe('createMessageStream', () => {
}).toThrow('tool_result blocks are not matching any tool_use from the previous message');
});
describe('terminal message guarantees', () => {
test('should yield exactly one terminal message for successful request', async () => {
const server = new Server({ name: 'test server', version: '1.0' }, { capabilities: {} });
const client = new Client({ name: 'test client', version: '1.0' }, { capabilities: { sampling: {} } });
describe('with tasks', () => {
let server: Server;
let client: Client;
let clientTransport: ReturnType<typeof InMemoryTransport.createLinkedPair>[0];
let serverTransport: ReturnType<typeof InMemoryTransport.createLinkedPair>[1];
client.setRequestHandler('sampling/createMessage', async () => ({
role: 'assistant',
content: { type: 'text', text: 'Response' },
model: 'test-model'
}));
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);
const stream = server.experimental.tasks.createMessageStream({
messages: [{ role: 'user', content: { type: 'text', text: 'Hello' } }],
maxTokens: 100
});
const allMessages = await toArrayAsync(stream);
expect(allMessages.length).toBe(1);
expect(allMessages[0].type).toBe('result');
const taskMessages = allMessages.filter(m => m.type === 'taskCreated' || m.type === 'taskStatus');
expect(taskMessages.length).toBe(0);
});
test('should yield error as terminal message when client returns error', async () => {
const server = new Server({ name: 'test server', version: '1.0' }, { capabilities: {} });
const client = new Client({ name: 'test client', version: '1.0' }, { capabilities: { sampling: {} } });
client.setRequestHandler('sampling/createMessage', async () => {
throw new Error('Simulated client error');
});
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);
const stream = server.experimental.tasks.createMessageStream({
messages: [{ role: 'user', content: { type: 'text', text: 'Hello' } }],
maxTokens: 100
});
const allMessages = await toArrayAsync(stream);
expect(allMessages.length).toBe(1);
expect(allMessages[0].type).toBe('error');
});
test('should yield exactly one terminal message with result', async () => {
const server = new Server({ name: 'test server', version: '1.0' }, { capabilities: {} });
const client = new Client({ name: 'test client', version: '1.0' }, { capabilities: { sampling: {} } });
client.setRequestHandler('sampling/createMessage', () => ({
model: 'test-model',
role: 'assistant' as const,
content: { type: 'text' as const, text: 'Response' }
}));
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);
const stream = server.experimental.tasks.createMessageStream({
messages: [{ role: 'user', content: { type: 'text', text: 'Message' } }],
maxTokens: 100
});
const messages = await toArrayAsync(stream);
const terminalMessages = messages.filter(m => m.type === 'result' || m.type === 'error');
expect(terminalMessages.length).toBe(1);
const lastMessage = messages.at(-1);
expect(lastMessage.type === 'result' || lastMessage.type === 'error').toBe(true);
if (lastMessage.type === 'result') {
expect((lastMessage.result as CreateMessageResult).content).toBeDefined();
}
});
});
describe('non-task request minimality', () => {
test('should yield only result message for non-task request', async () => {
const server = new Server({ name: 'test server', version: '1.0' }, { capabilities: {} });
const client = new Client({ name: 'test client', version: '1.0' }, { capabilities: { sampling: {} } });
client.setRequestHandler('sampling/createMessage', () => ({
model: 'test-model',
role: 'assistant' as const,
content: { type: 'text' as const, text: 'Response' }
}));
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);
const stream = server.experimental.tasks.createMessageStream({
messages: [{ role: 'user', content: { type: 'text', text: 'Message' } }],
maxTokens: 100
});
const messages = await toArrayAsync(stream);
const taskMessages = messages.filter(m => m.type === 'taskCreated' || m.type === 'taskStatus');
expect(taskMessages.length).toBe(0);
const resultMessages = messages.filter(m => m.type === 'result');
expect(resultMessages.length).toBe(1);
expect(messages.length).toBe(1);
});
});
describe('task-augmented request handling', () => {
test('should yield taskCreated and result for task-augmented request', async () => {
const clientTaskStore = new InMemoryTaskStore();
const server = new Server({ name: 'test server', version: '1.0' }, { capabilities: {} });
const client = new Client(
{ name: 'test client', version: '1.0' },
beforeEach(async () => {
server = new Server(
{ name: 'test server', version: '1.0' },
{
capabilities: {
sampling: {},
tasks: {
requests: {
sampling: { createMessage: {} }
}
taskStore: new InMemoryTaskStore()
}
},
taskStore: clientTaskStore
}
}
);
client.setRequestHandler('sampling/createMessage', async (request, extra) => {
const result = {
model: 'test-model',
role: 'assistant' as const,
content: { type: 'text' as const, text: 'Task response' }
};
client = new Client({ name: 'test client', version: '1.0' }, { capabilities: { sampling: {} } });
if (request.params.task && extra.task?.store) {
const task = await extra.task.store.createTask({ ttl: extra.task.requestedTtl });
await extra.task.store.storeTaskResult(task.taskId, 'completed', result);
return { task };
}
return result;
[clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
});
afterEach(async () => {
await server.close().catch(() => {});
await client.close().catch(() => {});
});
describe('terminal message guarantees', () => {
test('should yield exactly one terminal message for successful request', async () => {
client.setRequestHandler('sampling/createMessage', async () => ({
role: 'assistant',
content: { type: 'text', text: 'Response' },
model: 'test-model'
}));
await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);
const stream = server.experimental.tasks.createMessageStream({
messages: [{ role: 'user', content: { type: 'text', text: 'Hello' } }],
maxTokens: 100
});
const allMessages = await toArrayAsync(stream);
expect(allMessages.length).toBe(1);
expect(allMessages[0].type).toBe('result');
const taskMessages = allMessages.filter(m => m.type === 'taskCreated' || m.type === 'taskStatus');
expect(taskMessages.length).toBe(0);
});
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);
test('should yield error as terminal message when client returns error', async () => {
client.setRequestHandler('sampling/createMessage', async () => {
throw new Error('Simulated client error');
});
const stream = server.experimental.tasks.createMessageStream(
{
messages: [{ role: 'user', content: { type: 'text', text: 'Task-augmented message' } }],
await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);
const stream = server.experimental.tasks.createMessageStream({
messages: [{ role: 'user', content: { type: 'text', text: 'Hello' } }],
maxTokens: 100
},
{ task: { ttl: 60_000 } }
);
});
const messages = await toArrayAsync(stream);
const allMessages = await toArrayAsync(stream);
// Should have taskCreated and result
expect(messages.length).toBeGreaterThanOrEqual(2);
expect(allMessages.length).toBe(1);
expect(allMessages[0].type).toBe('error');
});
// First message should be taskCreated
expect(messages[0].type).toBe('taskCreated');
const taskCreated = messages[0] as { type: 'taskCreated'; task: Task };
expect(taskCreated.task.taskId).toBeDefined();
test('should yield exactly one terminal message with result', async () => {
client.setRequestHandler('sampling/createMessage', () => ({
model: 'test-model',
role: 'assistant' as const,
content: { type: 'text' as const, text: 'Response' }
}));
// Last message should be result
const lastMessage = messages.at(-1);
expect(lastMessage.type).toBe('result');
if (lastMessage.type === 'result') {
expect((lastMessage.result as CreateMessageResult).model).toBe('test-model');
}
await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);
clientTaskStore.cleanup();
const stream = server.experimental.tasks.createMessageStream({
messages: [{ role: 'user', content: { type: 'text', text: 'Message' } }],
maxTokens: 100
});
const messages = await toArrayAsync(stream);
const terminalMessages = messages.filter(m => m.type === 'result' || m.type === 'error');
expect(terminalMessages.length).toBe(1);
const lastMessage = messages.at(-1);
expect(lastMessage.type === 'result' || lastMessage.type === 'error').toBe(true);
if (lastMessage.type === 'result') {
expect((lastMessage.result as CreateMessageResult).content).toBeDefined();
}
});
});
describe('non-task request minimality', () => {
test('should yield only result message for non-task request', async () => {
client.setRequestHandler('sampling/createMessage', () => ({
model: 'test-model',
role: 'assistant' as const,
content: { type: 'text' as const, text: 'Response' }
}));
await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]);
const stream = server.experimental.tasks.createMessageStream({
messages: [{ role: 'user', content: { type: 'text', text: 'Message' } }],
maxTokens: 100
});
const messages = await toArrayAsync(stream);
const taskMessages = messages.filter(m => m.type === 'taskCreated' || m.type === 'taskStatus');
expect(taskMessages.length).toBe(0);
const resultMessages = messages.filter(m => m.type === 'result');
expect(resultMessages.length).toBe(1);
expect(messages.length).toBe(1);
});
});
describe('task-augmented request handling', () => {
test('should yield taskCreated and result for task-augmented request', async () => {
const clientTaskStore = new InMemoryTaskStore();
const taskClient = new Client(
{ name: 'test client', version: '1.0' },
{
capabilities: {
sampling: {},
tasks: {
taskStore: clientTaskStore,
requests: {
sampling: { createMessage: {} }
}
}
}
}
);
taskClient.setRequestHandler('sampling/createMessage', async (request, extra) => {
const result = {
model: 'test-model',
role: 'assistant' as const,
content: { type: 'text' as const, text: 'Task response' }
};
if (request.params.task && extra.task?.store) {
const task = await extra.task.store.createTask({ ttl: extra.task.requestedTtl });
await extra.task.store.storeTaskResult(task.taskId, 'completed', result);
return { task };
}
return result;
});
const [taskClientTransport, taskServerTransport] = InMemoryTransport.createLinkedPair();
await Promise.all([taskClient.connect(taskClientTransport), server.connect(taskServerTransport)]);
const stream = server.experimental.tasks.createMessageStream(
{
messages: [{ role: 'user', content: { type: 'text', text: 'Task-augmented message' } }],
maxTokens: 100
},
{ task: { ttl: 60_000 } }
);
const messages = await toArrayAsync(stream);
// Should have taskCreated and result
expect(messages.length).toBeGreaterThanOrEqual(2);
// First message should be taskCreated
expect(messages[0].type).toBe('taskCreated');
const taskCreated = messages[0] as { type: 'taskCreated'; task: Task };
expect(taskCreated.task.taskId).toBeDefined();
// Last message should be result
const lastMessage = messages.at(-1);
expect(lastMessage.type).toBe('result');
if (lastMessage.type === 'result') {
expect((lastMessage.result as CreateMessageResult).model).toBe('test-model');
}
clientTaskStore.cleanup();
await taskClient.close().catch(() => {});
});
});
});
});
@ -2362,10 +2375,11 @@ describe('Task-based execution', () => {
tools: {
call: {}
}
}
},
taskStore
}
},
taskStore
}
}
);
@ -2542,10 +2556,11 @@ describe('Task-based execution', () => {
tools: {
call: {}
}
}
},
taskStore
}
},
taskStore
}
}
);
@ -2719,10 +2734,11 @@ describe('Task-based execution', () => {
elicitation: {
create: {}
}
}
},
taskStore: clientTaskStore
}
},
taskStore: clientTaskStore
}
}
);
@ -2746,10 +2762,23 @@ describe('Task-based execution', () => {
return result;
});
const server = new Server({
name: 'test-server',
version: '1.0.0'
});
const server = new Server(
{
name: 'test-server',
version: '1.0.0'
},
{
capabilities: {
tasks: {
requests: {
elicitation: {
create: {}
}
}
}
}
}
);
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
@ -2799,10 +2828,11 @@ describe('Task-based execution', () => {
elicitation: {
create: {}
}
}
},
taskStore: clientTaskStore
}
},
taskStore: clientTaskStore
}
}
);
@ -2826,10 +2856,21 @@ describe('Task-based execution', () => {
return result;
});
const server = new Server({
name: 'test-server',
version: '1.0.0'
});
const server = new Server(
{
name: 'test-server',
version: '1.0.0'
},
{
capabilities: {
tasks: {
requests: {
elicitation: { create: {} }
}
}
}
}
);
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
@ -2877,10 +2918,11 @@ describe('Task-based execution', () => {
elicitation: {
create: {}
}
}
},
taskStore: clientTaskStore
}
},
taskStore: clientTaskStore
}
}
);
@ -2904,10 +2946,21 @@ describe('Task-based execution', () => {
return result;
});
const server = new Server({
name: 'test-server',
version: '1.0.0'
});
const server = new Server(
{
name: 'test-server',
version: '1.0.0'
},
{
capabilities: {
tasks: {
requests: {
elicitation: { create: {} }
}
}
}
}
);
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
@ -2957,10 +3010,11 @@ describe('Task-based execution', () => {
elicitation: {
create: {}
}
}
},
taskStore: clientTaskStore
}
},
taskStore: clientTaskStore
}
}
);
@ -3059,10 +3113,11 @@ describe('Task-based execution', () => {
tools: {
call: {}
}
}
},
taskStore
}
},
taskStore
}
}
);
@ -3198,10 +3253,11 @@ describe('Task-based execution', () => {
tools: {
call: {}
}
}
},
taskStore
}
},
taskStore
}
}
);
@ -3245,10 +3301,11 @@ describe('Task-based execution', () => {
elicitation: {
create: {}
}
}
},
taskStore: clientTaskStore
}
},
taskStore: clientTaskStore
}
}
);
@ -3302,10 +3359,11 @@ test('should respect client task capabilities', async () => {
elicitation: {
create: {}
}
}
},
taskStore: clientTaskStore
}
},
taskStore: clientTaskStore
}
}
);
@ -3414,7 +3472,16 @@ describe('elicitInputStream', () => {
let serverTransport: ReturnType<typeof InMemoryTransport.createLinkedPair>[1];
beforeEach(async () => {
server = new Server({ name: 'test server', version: '1.0' }, { capabilities: {} });
server = new Server(
{ name: 'test server', version: '1.0' },
{
capabilities: {
tasks: {
taskStore: new InMemoryTaskStore()
}
}
}
);
client = new Client(
{ name: 'test client', version: '1.0' },
@ -3643,12 +3710,12 @@ describe('elicitInputStream', () => {
capabilities: {
elicitation: { form: {} },
tasks: {
taskStore: clientTaskStore,
requests: {
elicitation: { create: {} }
}
}
},
taskStore: clientTaskStore
}
}
);

View file

@ -2035,10 +2035,11 @@ describe('Zod v4', () => {
tools: {
call: {}
}
}
},
taskStore
}
},
taskStore
}
}
);
@ -2104,10 +2105,11 @@ describe('Zod v4', () => {
tools: {
call: {}
}
}
},
taskStore
}
},
taskStore
}
}
);
@ -6367,10 +6369,11 @@ describe('Zod v4', () => {
tools: {
call: {}
}
}
},
taskStore
}
},
taskStore
}
}
);
@ -6469,10 +6472,11 @@ describe('Zod v4', () => {
tools: {
call: {}
}
}
},
taskStore
}
},
taskStore
}
}
);
@ -6574,10 +6578,11 @@ describe('Zod v4', () => {
tools: {
call: {}
}
}
},
taskStore
}
},
taskStore
}
}
);
@ -6694,10 +6699,11 @@ describe('Zod v4', () => {
tools: {
call: {}
}
}
},
taskStore
}
},
taskStore
}
}
);
@ -6797,10 +6803,11 @@ describe('Zod v4', () => {
tools: {
call: {}
}
}
},
taskStore
}
},
taskStore
}
}
);
@ -6895,10 +6902,11 @@ describe('Zod v4', () => {
tools: {
call: {}
}
}
},
taskStore
}
},
taskStore
}
}
);

View file

@ -39,11 +39,11 @@ describe('Task Lifecycle Integration Tests', () => {
}
},
list: {},
cancel: {}
cancel: {},
taskStore,
taskMessageQueue: new InMemoryTaskMessageQueue()
}
},
taskStore,
taskMessageQueue: new InMemoryTaskMessageQueue()
}
}
);
@ -300,10 +300,15 @@ describe('Task Lifecycle Integration Tests', () => {
describe('Task Cancellation', () => {
it('should cancel a working task and return the cancelled task', async () => {
const client = new Client({
name: 'test-client',
version: '1.0.0'
});
const client = new Client(
{
name: 'test-client',
version: '1.0.0'
},
{
capabilities: { tasks: {} }
}
);
const transport = new StreamableHTTPClientTransport(baseUrl);
await client.connect(transport);
@ -346,10 +351,15 @@ describe('Task Lifecycle Integration Tests', () => {
});
it('should reject cancellation of completed task with error code -32602', async () => {
const client = new Client({
name: 'test-client',
version: '1.0.0'
});
const client = new Client(
{
name: 'test-client',
version: '1.0.0'
},
{
capabilities: { tasks: {} }
}
);
const transport = new StreamableHTTPClientTransport(baseUrl);
await client.connect(transport);
@ -734,10 +744,15 @@ describe('Task Lifecycle Integration Tests', () => {
describe('Error Handling', () => {
it('should return error code -32602 for non-existent task in tasks/get', async () => {
const client = new Client({
name: 'test-client',
version: '1.0.0'
});
const client = new Client(
{
name: 'test-client',
version: '1.0.0'
},
{
capabilities: { tasks: {} }
}
);
const transport = new StreamableHTTPClientTransport(baseUrl);
await client.connect(transport);
@ -754,10 +769,15 @@ describe('Task Lifecycle Integration Tests', () => {
});
it('should return error code -32602 for non-existent task in tasks/cancel', async () => {
const client = new Client({
name: 'test-client',
version: '1.0.0'
});
const client = new Client(
{
name: 'test-client',
version: '1.0.0'
},
{
capabilities: { tasks: {} }
}
);
const transport = new StreamableHTTPClientTransport(baseUrl);
await client.connect(transport);
@ -1491,7 +1511,8 @@ describe('Task Lifecycle Integration Tests', () => {
},
{
capabilities: {
elicitation: {}
elicitation: {},
tasks: {}
}
}
);