Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .docker/sandbox/install-browser-agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -542,8 +542,33 @@ install_agent_browser_wrappers() {
fi
}

# Chromium's GPU child process drops all capabilities, so it is subject to
# normal permission bits when loading bundled Vulkan/SwiftShader libs under
# $HOME/.agent-browser. Allow others execute (traverse-only) on $HOME so the
# GPU process can reach those libraries. Files under $HOME keep their own
# modes; this repairs older snapshots still shipped with a 750 home from
# useradd.
ensure_home_dir_traversable_for_gpu_process() {
local home_dir="${HOME:-}"
local mode

if [ -z "$home_dir" ] || [ ! -d "$home_dir" ]; then
return 0
fi

mode="$(stat -c '%a' "$home_dir" 2>/dev/null || true)"
case "${mode: -1}" in
1|3|5|7)
return 0
;;
esac

chmod o+x "$home_dir" 2>/dev/null || true
}

main() {
ensure_owned_directory "$AGENT_BROWSER_INSTALL_ROOT"
ensure_home_dir_traversable_for_gpu_process

local real_cli_path
real_cli_path="$(find_real_agent_browser_cli_path)"
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

This file tracks product releases for Roomote (single monorepo version). Automated release entries are prepended by `pnpm run version`.

## 0.14.1 (2026-07-19)

### Patch changes

- Quote web UI follow-ups into Discord-linked task threads (name + text blockquote) before the agent's next reply, matching Slack behavior and preserving quotes across web snapshot resume.
- Stop stacking a second empty Discord question shell when request_user_input enriches options; edit the existing prompt so users see one question with real choices.
- Support structured request_user_input on Discord end-to-end: post option buttons, accept button or text answers, and resume the paused agent so answering no longer leaves the run waiting.
- Fix sandbox WebGL by making the home directory traversable for Chromium's GPU process
- Show self-review and PR review feedback summaries in the task web view for web-only tasks by always writing the summary into task message history, not only when a chat route exists.

## 0.14.0 (2026-07-19)

### Minor changes
Expand Down
20 changes: 20 additions & 0 deletions apps/api/src/handlers/discord/callback-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import {
handleDiscordRoutingCallback,
parseDiscordRouteCallbackData,
} from './routing-confirmation.js';
import {
hasPendingDiscordRequestUserInputCallback,
tryHandleDiscordRequestUserInputCallback,
} from './request-user-input.js';
import type { DiscordChannelContext } from './task-launch.js';
import {
discordMetadataForChannel,
Expand Down Expand Up @@ -370,6 +374,22 @@ export async function handleDiscordComponentInteraction(input: {
channel: DiscordChannelContext;
}): Promise<'handled' | 'unsupported'> {
const customId = input.interaction.data?.custom_id;
if (hasPendingDiscordRequestUserInputCallback(customId)) {
const sender = input.interaction.member?.user ?? input.interaction.user;
const mappedUserId = sender?.id
? await findDiscordMappedUserId(sender.id)
: null;
await tryHandleDiscordRequestUserInputCallback({
provider: input.provider,
applicationId: input.applicationId,
channel: input.channel,
interaction: input.interaction,
interactionDeferred: input.interactionDeferred,
customId,
userId: mappedUserId,
});
return 'handled';
}
const cancelRunId = parseCancelCallbackData(customId);
if (cancelRunId) {
await handleCancelCallback({ ...input, runId: cancelRunId });
Expand Down
23 changes: 23 additions & 0 deletions apps/api/src/handlers/discord/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
findCommunicationTaskRunBySourceEvent,
} from '../tasks/communication-task-run-lookup.js';
import { resumeCommunicationTaskFromSnapshot } from '../tasks/communication-snapshot-resume.js';
import { tryHandleDiscordRequestUserInputMessage } from './request-user-input.js';
import {
attachOutOfBandContextToCommunicationMessage,
releaseCommunicationOutOfBandClaim,
Expand Down Expand Up @@ -519,6 +520,28 @@ async function processDiscordGatewayEvent(event: DiscordGatewayEvent) {
runId: activeRun.id,
senderUserId,
});

if (message && queuedMessage) {
const handledRequestUserInput =
await tryHandleDiscordRequestUserInputMessage({
provider: resolved.provider,
applicationId: resolved.applicationId,
channel,
activeRun: { id: activeRun.id },
userId: senderUserId,
text: queuedMessage.text,
replyToMessageId: message.id,
});
if (handledRequestUserInput) {
return {
ok: true,
queued: true,
runId: activeRun.id,
requestUserInput: true,
};
}
}

// Mirror Slack: rebuild undelivered thread context + latest bot reply into
// the follow-up prompt so agents keep full Discord conversation context.
let continuationClaim: {
Expand Down
Loading
Loading