Skip to content

Commit db99e99

Browse files
committed
Change Discord Presentation Mode
1 parent 6efa796 commit db99e99

File tree

4 files changed

+72
-141
lines changed

4 files changed

+72
-141
lines changed

typescript/discord/media/embed.png

112 KB
Loading
318 KB
Loading

typescript/discord/media/video.mp4

8.25 MB
Binary file not shown.
Lines changed: 72 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { BrowserUse } from "browser-use-sdk";
2-
import { SlashCommandBuilder } from "discord.js";
2+
import { SlashCommandBuilder, EmbedBuilder } from "discord.js";
33

44
import { ExhaustiveSwitchCheck } from "../lib/types";
55
import type { Command } from "./types";
@@ -24,169 +24,100 @@ export const run: Command = {
2424

2525
const tick: { current: number } = { current: 0 };
2626

27-
const state: { current: BrowserState } = { current: null };
27+
const task = await browseruse.tasks.create({
28+
task: command,
29+
agentSettings: {
30+
llm: "o3",
31+
},
32+
});
33+
34+
const embed = new EmbedBuilder()
35+
.setTitle("🤖 Browser Use Task")
36+
.setDescription(`**Command:** ${command}\n**Task ID:** ${task.id}`)
37+
.setColor(0x0099ff)
38+
.addFields(
39+
{ name: "Status", value: "🔄 Starting...", inline: true },
40+
{ name: "Live Session", value: "⏳ Waiting...", inline: true },
41+
)
42+
.setTimestamp();
43+
44+
await interaction.reply({ embeds: [embed] });
2845

2946
poll: do {
3047
tick.current++;
3148

32-
let status: BrowserUse.TaskView;
33-
34-
// NOTE: We take action on each tick.
35-
if (state.current == null) {
36-
status = await browseruse.tasks.create({
37-
task: command,
38-
agentSettings: {
39-
llm: "o3",
40-
},
41-
});
42-
} else {
43-
status = (await browseruse.tasks.retrieve(state.current.taskId)) as BrowserUse.TaskView;
44-
}
45-
46-
const [newState, events] = reducer(state.current, { kind: "status", status });
47-
48-
for (const event of events) {
49-
switch (event.kind) {
50-
case "task_started":
51-
interaction.reply(`Browser Use Task started (${event.taskId})`);
52-
break;
53-
case "session_live_url_ready":
54-
interaction.followUp(`Watch live Browser Use session at ${event.liveUrl}`);
55-
break;
56-
case "task_step_completed":
57-
interaction.followUp(`[${event.step.url}] ${event.step.nextGoal}`);
58-
break;
59-
case "task_completed":
60-
interaction.followUp(event.output);
61-
break poll;
62-
default:
63-
throw new ExhaustiveSwitchCheck(event);
64-
}
65-
}
66-
67-
state.current = newState;
68-
69-
// LOGS
70-
71-
if (state.current != null) {
72-
console.log(`${state.current.taskId} | [${tick.current}] ${status.status} `.padEnd(100, "-"));
73-
for (const event of events) {
74-
console.log(`${state.current.taskId} | - ${event.kind}`);
75-
}
76-
} else {
77-
// NOTE: This should never happen!
78-
throw new Error("Task unexpectedly got negative status update...");
79-
}
80-
81-
// TIMER
49+
const status = (await browseruse.tasks.retrieve(task.id)) as BrowserUse.TaskView;
8250

83-
await new Promise((resolve) => setTimeout(resolve, 1000));
84-
} while (true);
51+
switch (status.status) {
52+
case "started":
53+
case "stopped":
54+
case "paused": {
55+
const liveUrl = status.sessionLiveUrl ?? "⏳ Waiting...";
8556

86-
if (state.current == null) {
87-
console.log(`TASK NOT STARTED`);
88-
} else {
89-
console.log(`${state.current.taskId} | [${tick.current}] DONE `.padEnd(100, "-"));
90-
}
91-
},
92-
};
57+
const description: string[] = [];
9358

94-
// Event Loop ----------------------------------------------------------------
59+
description.push(`**Command:** ${command}`);
60+
description.push(`**Task ID:** ${task.id}`);
9561

96-
type BrowserState = {
97-
taskId: string;
98-
sessionId: string;
62+
description.push("");
9963

100-
liveSessionUrl: string | null;
64+
if (status.steps) {
65+
for (const step of status.steps) {
66+
description.push(`- [${step.url}] ${step.nextGoal}`);
67+
}
68+
} else {
69+
description.push("No steps yet");
70+
}
10171

102-
steps: BrowserUse.TaskView.Step[];
72+
if (status.doneOutput) {
73+
description.push("");
74+
description.push(status.doneOutput);
75+
}
10376

104-
output: string | null;
105-
} | null;
77+
const embed = new EmbedBuilder()
78+
.setTitle("🤖 Browser Use Task")
79+
.setDescription(description.join("\n"))
80+
.setColor(0x0099ff)
81+
.addFields(
82+
{ name: "Status", value: "🔄 Running...", inline: true },
83+
{ name: "Live Session", value: liveUrl, inline: true },
84+
)
85+
.setTimestamp();
10686

107-
type BrowserAction = {
108-
kind: "status";
109-
status: BrowserUse.TaskView;
110-
};
87+
await interaction.editReply({ embeds: [embed] });
11188

112-
type ReducerEvent =
113-
| {
114-
kind: "task_started";
115-
taskId: string;
116-
sessionId: string;
117-
}
118-
| {
119-
kind: "session_live_url_ready";
120-
liveUrl: string;
121-
}
122-
| {
123-
kind: "task_step_completed";
124-
step: BrowserUse.TaskView.Step;
125-
}
126-
| {
127-
kind: "task_completed";
128-
output: string;
129-
};
130-
131-
function reducer(state: BrowserState, action: BrowserAction): [BrowserState, Array<ReducerEvent>] {
132-
switch (action.kind) {
133-
case "status": {
134-
if (state == null) {
135-
const liveUrl = action.status.sessionLiveUrl ?? null;
136-
137-
const state: BrowserState = {
138-
taskId: action.status.id,
139-
sessionId: action.status.sessionId,
140-
liveSessionUrl: liveUrl,
141-
steps: [],
142-
output: null,
143-
};
144-
145-
const events: Array<ReducerEvent> = [
146-
{ kind: "task_started", taskId: action.status.id, sessionId: action.status.sessionId },
147-
];
148-
149-
if (liveUrl != null) {
150-
events.push({ kind: "session_live_url_ready", liveUrl });
89+
break;
15190
}
15291

153-
return [state, events];
154-
}
92+
case "finished": {
93+
const output: string[] = [];
15594

156-
const events: Array<ReducerEvent> = [];
95+
output.push(`# Browser Use Task - ${task.id} ✅`);
96+
output.push(`## Task`);
97+
output.push(command);
15798

158-
const liveUrl = action.status.sessionLiveUrl ?? null;
99+
output.push("");
159100

160-
if (state.liveSessionUrl == null && liveUrl != null) {
161-
events.push({ kind: "session_live_url_ready", liveUrl });
162-
}
101+
output.push(`## Output`);
102+
output.push(status.doneOutput);
163103

164-
const steps = state.steps;
165-
if (action.status.steps != null) {
166-
const newSteps = action.status.steps.slice(state.steps.length);
104+
await interaction.editReply({ content: output.join("\n"), embeds: [] });
167105

168-
for (const step of newSteps) {
169-
steps.push(step);
170-
events.push({ kind: "task_step_completed", step });
106+
break poll;
171107
}
108+
default:
109+
throw new ExhaustiveSwitchCheck(status.status);
172110
}
173111

174-
const output = action.status.doneOutput && action.status.doneOutput.length > 0 ? action.status.doneOutput : null;
112+
// LOGS
113+
114+
console.log(`[${status.id}] (${tick.current}) ${status.status}`);
175115

176-
if (state.output == null && output != null) {
177-
events.push({ kind: "task_completed", output });
178-
}
116+
// TIMER
179117

180-
const newState: BrowserState = {
181-
...state,
182-
liveSessionUrl: liveUrl,
183-
steps: steps,
184-
output: output,
185-
};
118+
await new Promise((resolve) => setTimeout(resolve, 1000));
119+
} while (true);
186120

187-
return [newState, events];
188-
}
189-
default:
190-
throw new ExhaustiveSwitchCheck(action.kind);
191-
}
192-
}
121+
console.log("done");
122+
},
123+
};

0 commit comments

Comments
 (0)