Skip to content

Commit 11a2ae5

Browse files
committed
fix: restore try/catch in updateProgress, add actor tool task statusMessage test
1 parent 61c8181 commit 11a2ae5

File tree

3 files changed

+75
-21
lines changed

3 files changed

+75
-21
lines changed

src/utils/progress.ts

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,37 @@ export class ProgressTracker {
2828

2929
// Send progress notification only if progressToken and sendNotification are available
3030
if (this.progressToken && this.sendNotification) {
31-
const notification: ProgressNotification = {
32-
method: 'notifications/progress' as const,
33-
params: {
34-
progressToken: this.progressToken,
35-
progress: this.currentProgress,
36-
...(message && { message }),
37-
},
38-
// Per MCP spec: progress notifications during task execution should include related-task metadata
39-
...(this.taskId && {
40-
_meta: {
41-
'io.modelcontextprotocol/related-task': {
42-
taskId: this.taskId,
43-
},
31+
try {
32+
const notification: ProgressNotification = {
33+
method: 'notifications/progress' as const,
34+
params: {
35+
progressToken: this.progressToken,
36+
progress: this.currentProgress,
37+
...(message && { message }),
4438
},
45-
}),
46-
};
39+
// Per MCP spec: progress notifications during task execution should include related-task metadata
40+
...(this.taskId && {
41+
_meta: {
42+
'io.modelcontextprotocol/related-task': {
43+
taskId: this.taskId,
44+
},
45+
},
46+
}),
47+
};
4748

48-
await this.sendNotification(notification);
49+
await this.sendNotification(notification);
50+
} catch {
51+
// Silent fail - don't break execution
52+
}
4953
}
5054

5155
// Update task statusMessage if callback is provided
5256
if (this.onStatusMessage && message) {
53-
await this.onStatusMessage(message);
57+
try {
58+
await this.onStatusMessage(message);
59+
} catch {
60+
// Silent fail - don't break execution
61+
}
5462
}
5563
}
5664

tests/integration/suite.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2411,7 +2411,7 @@ export function createIntegrationTestsSuite(
24112411
expect(resultReceived).toBe(true);
24122412
});
24132413

2414-
it.only('should propagate statusMessage to tasks/get and tasks/list for internal tools in task mode', async () => {
2414+
it('should propagate statusMessage to tasks/get and tasks/list for internal tools in task mode', async () => {
24152415
client = await createClientFn({ tools: ['actors'] });
24162416

24172417
const stream = client.experimental.tasks.callToolStream(
@@ -2467,6 +2467,52 @@ export function createIntegrationTestsSuite(
24672467
expect(listTasksSawStatusMessage).toBe(true);
24682468
});
24692469

2470+
it('should propagate statusMessage to tasks/get and tasks/list for actor tools in task mode', async () => {
2471+
client = await createClientFn({ tools: [RAG_WEB_BROWSER] });
2472+
2473+
const stream = client.experimental.tasks.callToolStream(
2474+
{
2475+
name: actorNameToToolName(RAG_WEB_BROWSER),
2476+
arguments: {
2477+
query: 'https://apify.com',
2478+
},
2479+
},
2480+
CallToolResultSchema,
2481+
{
2482+
task: {
2483+
ttl: 60000,
2484+
},
2485+
},
2486+
);
2487+
2488+
let taskId: string | null = null;
2489+
let getTaskSawStatusMessage = false;
2490+
let listTasksSawStatusMessage = false;
2491+
for await (const message of stream) {
2492+
if (message.type === 'taskCreated') {
2493+
taskId = message.task.taskId;
2494+
} else if (message.type === 'taskStatus') {
2495+
if (message.task.statusMessage) {
2496+
getTaskSawStatusMessage = true;
2497+
2498+
if (!listTasksSawStatusMessage && taskId) {
2499+
const currentTaskId = taskId;
2500+
const tasksList = await client.experimental.tasks.listTasks();
2501+
const ourTask = tasksList.tasks.find((t) => t.taskId === currentTaskId);
2502+
if (ourTask?.statusMessage) {
2503+
listTasksSawStatusMessage = true;
2504+
}
2505+
}
2506+
}
2507+
} else if (message.type === 'error') {
2508+
throw message.error;
2509+
}
2510+
}
2511+
2512+
expect(getTaskSawStatusMessage).toBe(true);
2513+
expect(listTasksSawStatusMessage).toBe(true);
2514+
});
2515+
24702516
it.runIf(options.transport === 'stdio')('should use UI_MODE env var when CLI arg is not provided', async () => {
24712517
client = await createClientFn({ useEnv: true, uiMode: 'openai' });
24722518
const tools = await client.listTools();

tests/unit/utils.progress.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ describe('ProgressTracker', () => {
4848
});
4949
});
5050

51-
it('should propagate notification send errors to the caller', async () => {
51+
it('should handle notification send errors gracefully', async () => {
5252
const mockSendNotification = vi.fn().mockRejectedValue(new Error('Network error'));
5353
const tracker = new ProgressTracker({ progressToken: 'test-token', sendNotification: mockSendNotification });
5454

55-
// Errors propagate so the caller (startActorRunUpdates interval) can catch them
56-
await expect(tracker.updateProgress('Test')).rejects.toThrow('Network error');
55+
// Should not throw
56+
await expect(tracker.updateProgress('Test')).resolves.toBeUndefined();
5757
expect(mockSendNotification).toHaveBeenCalled();
5858
});
5959
});

0 commit comments

Comments
 (0)