Skip to content
This repository was archived by the owner on Mar 7, 2026. It is now read-only.

Commit b0ee1e6

Browse files
committed
Merge branch 'development'
2 parents 7157c65 + 7d46ae2 commit b0ee1e6

File tree

7 files changed

+47
-75
lines changed

7 files changed

+47
-75
lines changed

packages/bytebot-agent/src/agent/agent.computer-use.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ async function clickMouse(input: {
303303
action: 'click_mouse',
304304
coordinates,
305305
button,
306-
holdKeys,
306+
holdKeys: holdKeys && holdKeys.length > 0 ? holdKeys : undefined,
307307
clickCount,
308308
}),
309309
});
@@ -358,7 +358,7 @@ async function dragMouse(input: {
358358
action: 'drag_mouse',
359359
path,
360360
button,
361-
holdKeys,
361+
holdKeys: holdKeys && holdKeys.length > 0 ? holdKeys : undefined,
362362
}),
363363
});
364364
} catch (error) {
@@ -387,7 +387,7 @@ async function scroll(input: {
387387
coordinates,
388388
direction,
389389
scrollCount,
390-
holdKeys,
390+
holdKeys: holdKeys && holdKeys.length > 0 ? holdKeys : undefined,
391391
}),
392392
});
393393
} catch (error) {

packages/bytebot-agent/src/agent/agent.constants.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ CORE WORKING PRINCIPLES
5050
Use **exactly** the identifiers listed in **VALID KEYS** below when supplying \`keys\` to \`computer_type_keys\` or \`computer_press_keys\`. All identifiers come from nut-tree's \`Key\` enum; they are case-sensitive and contain *no spaces*.
5151
5. **Verify Every Step** - After each action:
5252
a. Take another screenshot.
53-
b. Confirm the expected state before continuing. If it failed, retry sensibly or abort with \`"status":"failed"\`.
53+
b. Confirm the expected state before continuing. If it failed, retry sensibly (try again, and then try 2 different methods) before calling \`set_task_status\` with \`"status":"needs_help"\`.
5454
6. **Efficiency & Clarity** - Combine related key presses; prefer scrolling or dragging over many small moves; minimise unnecessary waits.
55-
7. **Stay Within Scope** - Do nothing the user didn't request; don't suggest unrelated tasks.
55+
7. **Stay Within Scope** - Do nothing the user didn't request; don't suggest unrelated tasks. For form and login fields, don't fill in random data, unless explicitly told to do so.
5656
8. **Security** - If you see a password, secret key, or other sensitive information (or the user shares it with you), do not repeat it in conversation. When typing sensitive information, use \`computer_type_text\` with \`isSensitive\` set to \`true\`.
5757
9. **Consistency & Persistence** - Even if the task is repetitive, do not end the task until the user's goal is completely met. For bulk operations, maintain focus and continue until all items are processed.
5858
@@ -124,23 +124,18 @@ TASK LIFECYCLE TEMPLATE
124124
{ "name": "computer_read_file", "input": { "path": "/path/to/file" } }
125125
\`\`\`
126126
This tool reads files and returns them as document content blocks with base64 data, supporting various file types including documents (PDF, DOCX, TXT, etc.) and images (PNG, JPG, etc.).
127-
128-
8. **Ask for Help** - If you need clarification, invoke
127+
8. **Ask for Help** - If you need clarification, or if you are unable to fully complete the task, invoke
129128
\`\`\`json
130-
{ "name": "set_task_status", "input": { "status": "needs_help", "description": "Summary of help needed" } }
129+
{ "name": "set_task_status", "input": { "status": "needs_help", "description": "Summary of help or clarification needed" } }
131130
\`\`\`
132131
9. **Cleanup** - When the user's goal is met:
133132
• Close every window, file, or app you opened so the desktop is tidy.
134133
• Return to an idle desktop/background.
135-
10. **Terminate** - ONLY ONCE THE USER'S GOAL IS MET, As your final tool call and message, invoke
134+
10. **Terminate** - ONLY ONCE THE USER'S GOAL IS COMPLETELY MET, As your final tool call and message, invoke
136135
\`\`\`json
137136
{ "name": "set_task_status", "input": { "status": "completed", "description": "Summary of the task" } }
138137
\`\`\`
139-
Or, if the task is failed or unrecoverable, invoke
140-
\`\`\`json
141-
{ "name": "set_task_status", "input": { "status": "failed", "description": "Summary of the failure" } }
142-
\`\`\`
143-
No further actions or messages follow this call.
138+
No further actions or messages will follow this call.
144139
145140
**IMPORTANT**: For bulk operations like "visit each profile in the directory":
146141
- Do NOT mark as completed after just a few profiles

packages/bytebot-agent/src/agent/agent.processor.ts

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -355,25 +355,6 @@ export class AgentProcessor {
355355
},
356356
],
357357
});
358-
359-
switch (block.input.status) {
360-
case 'completed':
361-
await this.tasksService.update(taskId, {
362-
status: TaskStatus.COMPLETED,
363-
completedAt: new Date(),
364-
});
365-
break;
366-
case 'failed':
367-
await this.tasksService.update(taskId, {
368-
status: TaskStatus.FAILED,
369-
});
370-
break;
371-
case 'needs_help':
372-
await this.tasksService.update(taskId, {
373-
status: TaskStatus.NEEDS_HELP,
374-
});
375-
break;
376-
}
377358
}
378359
}
379360

@@ -394,11 +375,6 @@ export class AgentProcessor {
394375
completedAt: new Date(),
395376
});
396377
break;
397-
case 'failed':
398-
await this.tasksService.update(taskId, {
399-
status: TaskStatus.FAILED,
400-
});
401-
break;
402378
case 'needs_help':
403379
await this.tasksService.update(taskId, {
404380
status: TaskStatus.NEEDS_HELP,

packages/bytebot-agent/src/agent/agent.tools.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export const _clickMouseTool = {
8282
clickCount: {
8383
type: 'integer' as const,
8484
description: 'Number of clicks to perform (e.g., 2 for double-click)',
85+
default: 1,
8586
},
8687
},
8788
required: ['button', 'clickCount'],
@@ -318,13 +319,13 @@ export const _setTaskStatusTool = {
318319
properties: {
319320
status: {
320321
type: 'string' as const,
321-
enum: ['completed', 'failed', 'needs_help'],
322+
enum: ['completed', 'needs_help'],
322323
description: 'The status of the task',
323324
},
324325
description: {
325326
type: 'string' as const,
326327
description:
327-
'If the task is completed, a summary of the task. If the task is failed, a description of the failure.',
328+
'If the task is completed, a summary of the task. If the task needs help, a description of the issue or clarification needed.',
328329
},
329330
},
330331
required: ['status', 'description'],

packages/bytebot-agent/src/tasks/tasks.controller.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,6 @@ export class TasksController {
183183
return this.messagesService.findProcessedMessages(taskId, options);
184184
}
185185

186-
@Patch(':id')
187-
async update(
188-
@Param('id') id: string,
189-
@Body() updateTaskDto: UpdateTaskDto,
190-
): Promise<Task> {
191-
return this.tasksService.update(id, updateTaskDto);
192-
}
193-
194186
@Delete(':id')
195187
@HttpCode(HttpStatus.NO_CONTENT)
196188
async delete(@Param('id') id: string): Promise<void> {

packages/bytebot-agent/src/tasks/tasks.service.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -242,13 +242,15 @@ export class TasksService {
242242
throw new NotFoundException(`Task with ID ${id} not found`);
243243
}
244244

245-
const updatedTask = await this.prisma.task.update({
245+
let updatedTask = await this.prisma.task.update({
246246
where: { id },
247247
data: updateTaskDto,
248248
});
249249

250250
if (updateTaskDto.status === TaskStatus.COMPLETED) {
251251
this.eventEmitter.emit('task.completed', { taskId: id });
252+
} else if (updateTaskDto.status === TaskStatus.NEEDS_HELP) {
253+
updatedTask = await this.takeOver(id);
252254
} else if (updateTaskDto.status === TaskStatus.FAILED) {
253255
this.eventEmitter.emit('task.failed', { taskId: id });
254256
}
@@ -291,15 +293,6 @@ export class TasksService {
291293
});
292294

293295
this.tasksGateway.emitNewMessage(taskId, message);
294-
295-
if (task.status === TaskStatus.NEEDS_HELP) {
296-
await this.prisma.task.update({
297-
where: { id: taskId },
298-
data: {
299-
status: TaskStatus.RUNNING,
300-
},
301-
});
302-
}
303296
return task;
304297
}
305298

@@ -319,6 +312,7 @@ export class TasksService {
319312
where: { id: taskId },
320313
data: {
321314
control: Role.ASSISTANT,
315+
status: TaskStatus.RUNNING,
322316
},
323317
});
324318

packages/bytebot-ui/src/app/tasks/[id]/page.tsx

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,39 @@ export default function TaskPage() {
3939
} = useChatSession({ initialTaskId: taskId });
4040

4141
// Determine if task is inactive (show screenshot) or active (show VNC)
42-
const isTaskInactive =
43-
taskStatus === TaskStatus.COMPLETED ||
44-
taskStatus === TaskStatus.FAILED ||
45-
taskStatus === TaskStatus.CANCELLED;
42+
function isTaskInactive(): boolean {
43+
return (
44+
taskStatus === TaskStatus.COMPLETED ||
45+
taskStatus === TaskStatus.FAILED ||
46+
taskStatus === TaskStatus.CANCELLED
47+
);
48+
}
4649

4750
// Determine if user can take control
48-
const canTakeOver =
49-
control === Role.ASSISTANT && taskStatus === TaskStatus.RUNNING;
51+
function canTakeOver(): boolean {
52+
return control === Role.ASSISTANT && taskStatus === TaskStatus.RUNNING;
53+
}
5054

5155
// Determine if user has control or is in takeover mode
52-
const hasUserControl =
53-
control === Role.USER && taskStatus === TaskStatus.RUNNING;
56+
function hasUserControl(): boolean {
57+
return (
58+
control === Role.USER &&
59+
(taskStatus === TaskStatus.RUNNING ||
60+
taskStatus === TaskStatus.NEEDS_HELP)
61+
);
62+
}
5463

5564
// Determine if task can be cancelled
56-
const canCancel =
57-
taskStatus === TaskStatus.RUNNING || taskStatus === TaskStatus.NEEDS_HELP;
65+
function canCancel(): boolean {
66+
return (
67+
taskStatus === TaskStatus.RUNNING || taskStatus === TaskStatus.NEEDS_HELP
68+
);
69+
}
5870

5971
// Determine VNC mode - interactive when user has control, view-only otherwise
60-
const vncViewOnly = !hasUserControl;
72+
function vncViewOnly(): boolean {
73+
return !hasUserControl;
74+
}
6175

6276
// Use scroll screenshot hook for inactive tasks
6377
const { currentScreenshot } = useScrollScreenshot({
@@ -90,8 +104,8 @@ export default function TaskPage() {
90104
{/* Main container */}
91105
<div className="col-span-4">
92106
<DesktopContainer
93-
screenshot={isTaskInactive ? currentScreenshot : null}
94-
viewOnly={vncViewOnly}
107+
screenshot={isTaskInactive() ? currentScreenshot : null}
108+
viewOnly={vncViewOnly()}
95109
status={
96110
(() => {
97111
if (
@@ -110,7 +124,7 @@ export default function TaskPage() {
110124
})() as VirtualDesktopStatus
111125
}
112126
>
113-
{canTakeOver && (
127+
{canTakeOver() && (
114128
<Button
115129
onClick={handleTakeOverTask}
116130
variant="default"
@@ -125,12 +139,12 @@ export default function TaskPage() {
125139
Take Over
126140
</Button>
127141
)}
128-
{hasUserControl && (
142+
{hasUserControl() && (
129143
<Button onClick={handleResumeTask} variant="default" size="sm">
130144
Proceed
131145
</Button>
132146
)}
133-
{canCancel && (
147+
{canCancel() && (
134148
<DropdownMenu>
135149
<DropdownMenuTrigger asChild>
136150
<Button variant="outline" size="icon">
@@ -158,7 +172,7 @@ export default function TaskPage() {
158172
{/* Messages scrollable area */}
159173
<div
160174
ref={chatContainerRef}
161-
className="min-h-0 flex-1 overflow-scroll px-4 hide-scrollbar"
175+
className="hide-scrollbar min-h-0 flex-1 overflow-scroll px-4"
162176
>
163177
<ChatContainer
164178
scrollRef={chatContainerRef}

0 commit comments

Comments
 (0)