Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5684bd8
[Feat] Add feature-demo skill for polished, narrated demo videos
mrubens Aug 8, 2026
d93c834
[Fix] Report the TTS model so timing fit picks the right pace
mrubens Aug 8, 2026
e809dc8
[Refactor] Frame the render project as an adaptable reference template
mrubens Aug 8, 2026
b35d8c7
[Refactor] Hardcode the narration model to eleven_multilingual_v2
mrubens Aug 8, 2026
b995257
[Fix] Address review feedback on capture and timing fit
mrubens Aug 8, 2026
3e7f7bc
[Docs] Regenerate the cookbook index and clean up the recipe copy
mrubens Aug 8, 2026
169aa52
[Fix] Resolve the Remotion headless-shell binary by search
mrubens Aug 8, 2026
88a7f37
[Fix] Anchor narration to when each zoom lands, not the caption fade-in
mrubens Aug 8, 2026
8dc12b2
[Fix] Keep screencast frames flowing on statically-rendered pages
mrubens Aug 8, 2026
b17b6c4
[Fix] Sanction the staged feature-demo runner in the proof-runner prompt
mrubens Aug 8, 2026
b3175e1
[Docs] Route WebGL-surface recording stalls to a specific blocker
mrubens Aug 8, 2026
d293811
[Fix] Bind the proof-runner capture sanction to a content digest
mrubens Aug 8, 2026
9157936
[Feat] Add ElevenLabs as a built-in credential-only integration
mrubens Aug 8, 2026
bbcbb92
[Fix] Exclude credential-only integrations from MCP proxy registration
mrubens Aug 8, 2026
c86f1b8
[Fix] Drop credential-only integrations from the worker proxy map too
mrubens Aug 8, 2026
6b206ef
[Fix] Close the verify/execute race on the staged capture runner
mrubens Aug 8, 2026
48921e6
[Fix] Update proof-runner prompt test for the reworded sanction
mrubens Aug 8, 2026
51950ca
[Fix] Atomically hash-and-execute the staged capture runner
mrubens Aug 8, 2026
7c3998a
[Feat] Record feature demos headed so GPU canvases don't stall
mrubens Aug 8, 2026
2fa47ef
[Fix] Let the agent-browser wrapper honor an explicit --headed opt-in
mrubens Aug 8, 2026
d41b387
[Fix] Reap zombie browser processes and force fresh daemon for headed…
mrubens Aug 8, 2026
0abbb3a
[Fix] Bump agent-browser 0.27.0 -> 0.33.2 for headed auto-Xvfb
mrubens Aug 8, 2026
58e37aa
[Feat] Plan feature demos through the advisor subagent
mrubens Aug 8, 2026
fe37ea3
[Fix] Give external-page demos a proof-runner selector-verification path
mrubens Aug 8, 2026
2be7dcb
[Perf] Pre-install feature-demo render deps in the worker image
mrubens Aug 8, 2026
86e5099
[Fix] External-page selectors validate via capture's own loud failure
mrubens Aug 8, 2026
b27d504
[Refactor] Install only the three relevant Remotion skills for adapta…
mrubens Aug 8, 2026
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: 23 additions & 2 deletions .docker/sandbox/install-browser-agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ set -euo pipefail
# 1. Worker image builds (Dockerfiles) to prebake browser automation.
# 2. Worker setup compatibility fallbacks on older Linux images.

AGENT_BROWSER_VERSION="${AGENT_BROWSER_VERSION:-0.27.0}"
AGENT_BROWSER_VERSION="${AGENT_BROWSER_VERSION:-0.33.2}"
AGENT_BROWSER_INSTALL_ROOT="${AGENT_BROWSER_INSTALL_ROOT:-/opt/agent-browser}"
AGENT_BROWSER_EXECUTABLE_PATH="${AGENT_BROWSER_EXECUTABLE_PATH:-${AGENT_BROWSER_INSTALL_ROOT}/chrome}"
AGENT_BROWSER_SAVED_CLI_PATH="${AGENT_BROWSER_SAVED_CLI_PATH:-${AGENT_BROWSER_INSTALL_ROOT}/.cli-path}"
Expand Down Expand Up @@ -374,21 +374,35 @@ collect_cli_browser_args() {
local i=0
AGENT_BROWSER_EXEC_ARGS=()
AGENT_BROWSER_FORWARD_ARGS=()
# Default headless; a caller may opt a single invocation into headed mode
# (e.g. the feature-demo capture runner, so GPU-backed canvases present to
# the compositor). On displayless Linux agent-browser auto-starts Xvfb.
AGENT_BROWSER_WANT_HEADED=0

while [ "$i" -lt "${#args[@]}" ]; do
local arg="${args[$i]}"

case "$arg" in
--headed)
AGENT_BROWSER_WANT_HEADED=1
AGENT_BROWSER_FORWARD_ARGS+=("$arg")
if [ "$i" -lt $(( ${#args[@]} - 1 )) ]; then
case "${args[$((i + 1))]}" in
true|false)
i=$((i + 1))
[ "${args[$i]}" = false ] && AGENT_BROWSER_WANT_HEADED=0
AGENT_BROWSER_FORWARD_ARGS+=("${args[$i]}")
;;
esac
fi
;;
--headed=false)
AGENT_BROWSER_WANT_HEADED=0
AGENT_BROWSER_FORWARD_ARGS+=("$arg")
;;
--headed=*)
AGENT_BROWSER_WANT_HEADED=1
AGENT_BROWSER_FORWARD_ARGS+=("$arg")
;;
--args)
AGENT_BROWSER_FORWARD_ARGS+=("$arg")
Expand Down Expand Up @@ -512,7 +526,14 @@ if should_clear_seed_cache; then
fi

resolve_cli_paths
export AGENT_BROWSER_HEADED=false
# Preview-cookie seeding above always runs headless (inline env). The task
# command itself honors an explicit --headed opt-in; everything else stays
# headless as before.
if [ "${AGENT_BROWSER_WANT_HEADED:-0}" = 1 ]; then
export AGENT_BROWSER_HEADED=true
else
export AGENT_BROWSER_HEADED=false
fi
exec "$AGENT_BROWSER_BIN" "${AGENT_BROWSER_FORWARD_ARGS[@]}"
EOF_WRAPPER
}
Expand Down
1 change: 1 addition & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
".env.*",
".qdrant",
"packages/cloud-agents/src/server/workflows/skills/standard/agent-browser",
"packages/cloud-agents/src/server/workflows/skills/standard/feature-demo",
".vscode",
".git",
"**/*.{md,mdx,yml,yaml,html,htm,toml,svg,graphql,gql}"
Expand Down
1 change: 1 addition & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"apps/docs/**",
"apps/marketing/**",
"packages/cloud-agents/src/server/workflows/skills/standard/agent-browser/**",
"packages/cloud-agents/src/server/workflows/skills/standard/feature-demo/**",
"apps/codex-acp/target/**",
"**/next-env.d.ts",
"deploy/**"
Expand Down
3 changes: 3 additions & 0 deletions apps/api/src/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ export { mcpRouting } from './mcp/routing';
// inference gateway
export { inference } from './inference';

// narration tts
export { tts } from './tts';

// task runs
export { taskRunsRouter } from './task-runs';

Expand Down
10 changes: 8 additions & 2 deletions apps/api/src/handlers/mcp/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import {
areCuratedIntegrationsDisabled,
isCustomMcpDisabled,
} from '@roomote/env';
import { isNativeMcpIntegration, MCP_INTEGRATIONS } from '@roomote/types';
import {
isCredentialOnlyMcpIntegration,
isNativeMcpIntegration,
MCP_INTEGRATIONS,
} from '@roomote/types';

import type { Variables } from '../../types';

Expand Down Expand Up @@ -66,7 +70,9 @@ mcp.route('/vercel', vercelMcp);

for (const integration of MCP_INTEGRATIONS.filter(
(candidate) =>
!isNativeMcpIntegration(candidate) && candidate.id !== 'linear',
!isNativeMcpIntegration(candidate) &&
!isCredentialOnlyMcpIntegration(candidate) &&
candidate.id !== 'linear',
)) {
mcp.route(
`/${integration.id}`,
Expand Down
193 changes: 193 additions & 0 deletions apps/api/src/handlers/tts/__tests__/tts.test.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 67 additions & 0 deletions apps/api/src/handlers/tts/connection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { areCuratedIntegrationsDisabled, Env } from '@roomote/env';
import {
and,
db,
deploymentMcpEnablements,
eq,
isNull,
mcpConnections,
} from '@roomote/db/server';
import { decrypt } from '@roomote/db/encryption';
import { isMcpConnectionElevenLabsConfig } from '@roomote/types';

type ElevenLabsCredentials = {
apiKey: string;
voiceId: string;
};

/**
* Resolves narration TTS credentials for the deployment.
*
* The admin-configured ElevenLabs integration (Settings → Integrations) is
* the primary source; the `R_ELEVENLABS_*` environment variables remain an
* operator fallback. Returns undefined when neither is configured — the
* feature is off and the endpoint 404s.
*
* The integration is credential-only: this control-plane resolver is its
* single consumer, and the connection is deliberately excluded from agent
* MCP config delivery, so the key never travels toward a task sandbox.
*/
export async function resolveElevenLabsCredentials(): Promise<
ElevenLabsCredentials | undefined
> {
if (!areCuratedIntegrationsDisabled(Env.R_CURATED_INTEGRATIONS_DISABLED)) {
const connection = await db.query.mcpConnections.findFirst({
where: and(
eq(mcpConnections.mcpId, 'elevenlabs'),
isNull(mcpConnections.userId),
eq(mcpConnections.enabled, true),
eq(mcpConnections.authStatus, 'authenticated'),
),
});

if (connection && isMcpConnectionElevenLabsConfig(connection.authConfig)) {
const enablement = await db.query.deploymentMcpEnablements.findFirst({
where: eq(deploymentMcpEnablements.mcpId, 'elevenlabs'),
});

if (enablement?.enabled !== false) {
const apiKey = decrypt(connection.authConfig.encryptedApiKey).trim();
const voiceId = connection.authConfig.voiceId.trim();

if (apiKey && voiceId) {
return { apiKey, voiceId };
}
}
}
}

if (Env.R_ELEVENLABS_API_KEY && Env.R_ELEVENLABS_VOICE_ID) {
return {
apiKey: Env.R_ELEVENLABS_API_KEY,
voiceId: Env.R_ELEVENLABS_VOICE_ID,
};
}

return undefined;
}
Loading
Loading