From 52cb582ae2838d9a13a7722981e6de6cbf4d7f91 Mon Sep 17 00:00:00 2001 From: "@mrubens" <2600+mrubens@users.noreply.github.com> Date: Fri, 11 Sep 2026 00:10:27 +0000 Subject: [PATCH 1/4] chore: release Roomote 1.7.0 --- .changeset/quiet-drafts-stay-put.md | 5 -- .changeset/unify-skills-settings.md | 5 -- CHANGELOG.md | 45 ++++++++++ apps/docs/automations.mdx | 11 ++- apps/docs/communications.mdx | 17 ++-- apps/docs/cost-analytics.mdx | 20 +++-- apps/docs/environment-variables.mdx | 2 +- apps/docs/environments/definition.mdx | 7 +- apps/docs/fast-sessions.mdx | 6 ++ apps/docs/integrations/custom-mcp-servers.mdx | 7 +- apps/docs/integrations/index.mdx | 2 +- apps/docs/integrations/voice.mdx | 2 +- apps/docs/logo/integrations/agentmail.svg | 18 ++-- apps/docs/logo/integrations/voice.svg | 8 -- apps/docs/models.mdx | 8 ++ apps/docs/snippets/integration-name.jsx | 2 +- apps/docs/source-control.mdx | 14 +++ apps/docs/voice.mdx | 8 +- .../settings/ExperimentalSettings.tsx | 69 --------------- .../pages/ExperimentalSettingsPage.tsx | 3 +- .../settings/settings-navigation.test.ts | 4 +- .../settings/settings-navigation.ts | 3 +- .../experimental-settings/index.test.ts | 86 ------------------- .../commands/experimental-settings/index.ts | 63 -------------- apps/web/src/trpc/routers/_app.ts | 15 ---- package.json | 2 +- packages/db/package.json | 1 - .../db/src/lib/model-runtime-config.test.ts | 40 --------- packages/db/src/lib/model-runtime-config.ts | 16 +--- .../src/__tests__/config.test.ts | 11 +-- .../__tests__/metadata-descriptions.test.ts | 10 +-- packages/feature-flags/src/config.ts | 6 -- packages/feature-flags/src/index.ts | 9 -- packages/feature-flags/src/types.ts | 6 +- pnpm-lock.yaml | 3 - 35 files changed, 136 insertions(+), 398 deletions(-) delete mode 100644 .changeset/quiet-drafts-stay-put.md delete mode 100644 .changeset/unify-skills-settings.md delete mode 100644 apps/docs/logo/integrations/voice.svg delete mode 100644 apps/web/src/components/settings/ExperimentalSettings.tsx delete mode 100644 apps/web/src/trpc/commands/experimental-settings/index.test.ts delete mode 100644 apps/web/src/trpc/commands/experimental-settings/index.ts diff --git a/.changeset/quiet-drafts-stay-put.md b/.changeset/quiet-drafts-stay-put.md deleted file mode 100644 index 9713777be7..0000000000 --- a/.changeset/quiet-drafts-stay-put.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@roomote/web": patch ---- - -Keep pull request metadata refreshes state-neutral and distinguish later opt-in clean-review promotion from the refresh itself. diff --git a/.changeset/unify-skills-settings.md b/.changeset/unify-skills-settings.md deleted file mode 100644 index 577f59b404..0000000000 --- a/.changeset/unify-skills-settings.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@roomote/web": patch ---- - -Unify shared and environment-specific skills in one searchable Settings catalog with availability filters and a marketplace dialog. diff --git a/CHANGELOG.md b/CHANGELOG.md index ed2b670aa2..7c6c4ad1df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,51 @@ This file tracks product releases for Roomote (single monorepo version). Automated release entries are prepended by `pnpm run version`. +## 1.7.0 (2026-09-11) + +Roomote 1.7 adds natural voice and email conversations, smarter follow-through for delegated work, richer automation controls, and clearer usage insights. + +### Highlights + +- Talk with Fast Sessions through GPT-Live voice calls, or start and continue Roomote work over email with AgentMail. +- Let Fast quietly follow delegated coding tasks, surface meaningful developments, and correct work that drifts from the request. +- Add natural-language routing rules to built-in automations and manage existing pull requests across supported providers. +- Track token usage alongside spend in Cost Analytics, with daily trends and detailed provider and model breakdowns. + +### Minor changes + +- Use Email through AgentMail as a replyable Roomote communications channel, with inbox-scoped setup, durable threaded delivery, signed answers, and verified-address safeguards. +- Built-in automations can use natural-language Additional rules for repository scope, per-repository routing, and report guidance. +- Track token usage alongside spend in Cost Analytics with a total-token trend line, provider and model totals and averages, and token-aware drilldowns. +- DeepSeek V4.1 Flash replaces the dated Flash recommendation across OpenRouter, Vercel AI Gateway, and OpenCode Go. +- Fast Sessions quietly follow launched coding tasks, report meaningful developments, and apply evidence-backed corrections until the work settles. +- Agents can close, reopen, retarget, and edit existing pull requests across supported source-control providers without creating replacements. +- Weekly Manager Stats includes a daily created-versus-merged pull request chart and starts enabled on new deployments once a destination is configured. +- Unify shared and environment-specific skills in one searchable Settings catalog with availability filters and a marketplace dialog. +- Talk naturally with Roomote from Fast Sessions using GPT-Live, with full-duplex audio, live transcription, interruptions, and deployment-wide Voice setup in Settings. + +### Patch changes + +- Custom automation task models can be changed only by the automation owner or an administrator. +- Saved automation cards show cadence in the deployment scheduling timezone used for execution. +- Fast Sessions can manage reminders and automations directly again without a scheduling-discovery step. +- Fast Sessions can use deployment-wide custom remote MCP integrations without exposing upstream credentials. +- Fast Sessions honor saved Routing Rules when selecting an environment or delegated coding-task model. +- Source-control and Linear webhook redeliveries no longer risk repeating actions when the original audit outcome was not finalized. +- Blank slate tasks no longer expose internal repository sentinels in task headers and filters. +- Independent Slack suggested tasks start in separate execution threads and Sessions instead of sharing task context. +- Communication replies use compact live footers that keep running-task counts, pull request links, and Session links current as work starts and finishes. +- Preview Markdown artifacts directly in task and Session galleries before opening them. +- Coding tasks recover from exhausted transient OpenCode connection resets instead of stopping without a useful Session handoff. +- Preview status and failure pages provide consistent responsive branding, explanations, and recovery actions across desktop and mobile. +- Keep pull request metadata refreshes state-neutral and distinguish later opt-in clean-review promotion from the refresh itself. +- Custom automation cards refresh persisted results after Run now without requiring a page reload. +- Slack requests no longer receive a redundant eyes reaction while Roomote is working. +- Connected Sentry integrations expose the full admin-approved tool catalog instead of a stale static allowlist. +- Open a user's Sessions directly from their avatar in Session viewers and task messages. +- Automatic task follow-through timers stay out of the Session reminder list while user-created timer receipts clearly describe each action and reused schedule. +- The Automations list combines built-in and custom entries with consistent search, columns, responsive text, and alphabetical ordering. + ## 1.6.0 (2026-09-09) Roomote 1.6 adds flexible sandbox and public-repository work, native conversation charts, leaner scheduling discovery, and more reliable Sessions and skill management. diff --git a/apps/docs/automations.mdx b/apps/docs/automations.mdx index bfda383e67..121df809c4 100644 --- a/apps/docs/automations.mdx +++ b/apps/docs/automations.mdx @@ -148,9 +148,7 @@ Each automation card summarizes its cadence, workspace target, report destinatio creator, and most recent run. Blank slate runs do not clone repositories or require source-control credentials. -Use **View previous runs** on an automation card to open the task list -filtered to that automation's runs. For a custom automation, the history is -scoped to that specific automation rather than all custom automations. +Use the Sessions list and its automation filters when you need run history. When creating an automation through Roomote chat, ask for **suggested tasks** or **launchable follow-ups** if qualifying findings should become tasks that @@ -166,9 +164,10 @@ the automation only needs a specific repository set. Suggestions can accompany the Session's report after a delegated task finishes, not just its initial response. Accepting one keeps the follow-up in the -originating Session, so earlier findings remain in context. In Slack, launches -reuse that Session's report thread when it is available. Thread or topic -placement on other providers depends on the provider and execution target. +report context through a link without sharing execution context with another +suggestion. In Slack, each accepted suggestion starts a separate top-level +execution thread and Session. Thread or topic placement on other providers +depends on the provider and execution target. For a custom automation you manage, choose **Custom schedule** and enter either a standard five-field cron expression or a natural-language schedule such as “weekdays at diff --git a/apps/docs/communications.mdx b/apps/docs/communications.mdx index 002b0b3e7b..ebf2c374c7 100644 --- a/apps/docs/communications.mdx +++ b/apps/docs/communications.mdx @@ -23,7 +23,7 @@ attention. | | Teams that use Microsoft 365, Teams channels, and Microsoft Entra accounts | Microsoft can also be used for sign-in and account linking. | | | Lightweight personal, group, or forum-topic chat access | Telegram is a messaging provider, not a sign-in provider. | | | Communities and teams that organize work in channels, threads, and forums | Discord is a messaging provider, not a sign-in provider. | -| | Low-frequency task requests and results over email | Email conversations are replyable in both directions; not a sign-in provider. | +| | Low-frequency task requests and results over email | Email conversations are replyable in both directions; not a sign-in provider. | Configure communications providers from **Settings > Communications**. @@ -55,20 +55,19 @@ the exact suggestion you want by reacting to its message: - on Telegram, add a new 👍 reaction or use the suggestion's **Start** button The person starting the suggestion must have a linked Roomote account. Roomote -also needs an environment that can run the suggestion's target repository. A -suggestion with a pinned workspace starts its task inside the Session that -produced the report, so the task, the report, and any follow-up conversation -share one transcript. +also needs an environment that can run the suggestion's target repository. +Each accepted Slack suggestion starts in its own top-level execution thread and +Session, so independent follow-ups do not share task context with each other. Configured **Call Roomote via emoji** automations are separate from these suggestion reactions. When the suggestion is not pinned to an execution target, Fast-capable chat surfaces start it in Fast so Roomote can answer or delegate as needed. A pinned environment, repository-only surface, or provider without Fast support starts -the coding task directly. Suggested work remains connected to the Session that -produced the report. In Slack, suggestions with an available origin Session -continue in its report thread. Thread or topic placement for other launches -depends on the provider and execution target. +the coding task directly. The launch links back to the originating report for +context, while its execution and follow-up conversation remain isolated. Thread +or topic placement on providers other than Slack depends on the provider and +execution target. ## React to Roomote replies diff --git a/apps/docs/cost-analytics.mdx b/apps/docs/cost-analytics.mdx index b0b1b874a4..3af23ed69a 100644 --- a/apps/docs/cost-analytics.mdx +++ b/apps/docs/cost-analytics.mdx @@ -5,9 +5,9 @@ description: Review Roomote inference spend by type, source, environment, provid --- Cost Analytics helps deployment teams understand how Roomote uses inference -across tasks, Fast sessions, and automations. It reports the cost of -recorded model usage in US dollars, so you can spot the environments, models, -and work types that drive spend. +across tasks, Fast sessions, and automations. It reports cost in US dollars and +token usage, so you can spot the environments, models, and work types that drive +spend or high-volume inference. Any signed-in deployment user can open **Analytics** from the dashboard. The page opens to **Costs** by default. @@ -23,6 +23,7 @@ recorded inference usage. Use it to answer questions such as: - whether a particular environment or model is driving costs - how usage differs between people and automations - how a provider's cost changes over time +- how token volume changes even when a request has no recorded price The view starts grouped by **Type**. It distinguishes manual and automated tasks, **Session** orchestration, **Memories** synthesis, and other **Non-task @@ -34,6 +35,11 @@ model and provider. The source also appears in the detail drilldown. Choose a time range before comparing periods so the chart and breakdown use the same window. +The chart overlays a **Total tokens** trend line on the cost bars. Its tooltip +shows token and cost totals for the same day and grouping. The breakdown table +includes **Total tokens** and **Avg tokens / task** alongside cost, and selecting +a chart segment or table value opens the matching token-aware detail rows. + Analytics date presets and daily chart buckets use the web server's timezone, including daylight-saving transitions. Costs, Tasks, and PR analytics use the same calendar-day boundaries; these are not based on each viewer's browser @@ -52,6 +58,8 @@ providers. It is separate from [Anonymous Analytics](/anonymous-analytics): cost data stays inside your deployment for your team to review, while anonymous analytics is optional product telemetry sent to the Roomote team. -If a provider does not report pricing or usage for a request, that request -cannot contribute a cost to the view. Use provider and model filters to narrow -an investigation when totals do not match an external provider invoice. +If a provider reports tokens but no price for a request, that activity appears +in token totals even though it contributes no cost. A request with neither +pricing nor token usage cannot contribute to those metrics. Use provider and +model filters to narrow an investigation when totals do not match an external +provider invoice. diff --git a/apps/docs/environment-variables.mdx b/apps/docs/environment-variables.mdx index 57c655b072..518fc62feb 100644 --- a/apps/docs/environment-variables.mdx +++ b/apps/docs/environment-variables.mdx @@ -372,7 +372,7 @@ as per-task auth tokens or workspace paths. | `R_ALLOWED_EMAILS` | Optional | Comma-separated email allowlist for deployments that restrict sign-in by email. | | `R_ELEVENLABS_API_KEY` | Optional | ElevenLabs API key for narrated feature-demo videos. The key stays on the control plane; sandboxes reach text-to-speech only through an authenticated Roomote endpoint. A key scoped to text-to-speech only is sufficient and recommended. | | `R_ELEVENLABS_VOICE_ID` | Optional | ElevenLabs voice ID used for feature-demo narration. Required alongside the API key for narration to be available. | -| `R_VOICE_OPENAI_API_KEY` | Optional | OpenAI key dedicated to GPT-Live voice conversations. Falls back to `OPENAI_API_KEY` when unset and requires project access to `gpt-live-1`. The key stays on the control plane; browsers receive only a server-negotiated WebRTC session answer. | +| `R_VOICE_OPENAI_API_KEY` | Optional | OpenAI key dedicated to GPT-Live voice conversations. It does not fall back to `OPENAI_API_KEY` and requires project access to `gpt-live-1`. The key stays on the control plane; browsers receive only a server-negotiated WebRTC session answer. | During Microsoft Teams setup, Roomote uses the Microsoft Entra app values for the Teams bot by default. Use **Show advanced config** after the Directory diff --git a/apps/docs/environments/definition.mdx b/apps/docs/environments/definition.mdx index a8b40594c4..255daef38f 100644 --- a/apps/docs/environments/definition.mdx +++ b/apps/docs/environments/definition.mdx @@ -381,11 +381,14 @@ repository has a known trap, state it plainly. Admins can configure natural-language routing rules from **Settings → Environments**. Each rule maps a description, such as “Messages sent in the hospital-bugs Slack channel,” to an environment or the broad **All repositories** -workspace. +workspace. A rule can also recommend a coding model for work that Fast delegates. Rules are guidance rather than exact string matchers. An environment explicitly named in a request takes precedence, and a specific rule takes precedence over a -catch-all default. +catch-all default. Fast evaluates the saved rules when it chooses an environment +or model for a delegated task; they do not override a model or environment the +user explicitly requested. Rules that point to a deleted environment are ignored +until an admin updates or removes them. ## MCP servers diff --git a/apps/docs/fast-sessions.mdx b/apps/docs/fast-sessions.mdx index 1aa567f52b..51b736435f 100644 --- a/apps/docs/fast-sessions.mdx +++ b/apps/docs/fast-sessions.mdx @@ -138,6 +138,12 @@ reply in the transcript. Delegated tasks also report their completion, blockers, and relevant results back into the parent Session; open the task workspace when you need its full logs or diff. +Fast quietly follows the coding tasks it launches after the conversation becomes +idle. It reports meaningful progress, blockers, and questions that need input, +and can send an evidence-backed correction when a task is drifting from the +request. Routine status stays quiet. Follow-through stops when the Session's +coding work settles instead of leaving a recurring monitor behind. + **Session info** shows the total inference cost for the conversation and its attached tasks. Open the cost breakdown to separate direct Session orchestration from each task's usage. diff --git a/apps/docs/integrations/custom-mcp-servers.mdx b/apps/docs/integrations/custom-mcp-servers.mdx index 204ad10c5c..c3daee5a61 100644 --- a/apps/docs/integrations/custom-mcp-servers.mdx +++ b/apps/docs/integrations/custom-mcp-servers.mdx @@ -5,8 +5,9 @@ description: 'Connect MCP servers that are not in the built-in catalog' Custom MCP servers let agents use services that Roomote does not ship a built-in integration for. Deployment admins configure them under -**Settings → Integrations → Custom MCP Servers**, and they become available to -agents in every task. +**Settings → Integrations → Custom MCP Servers**. Remote servers become +available to both Fast Sessions and sandbox tasks. Local stdio servers need a +task sandbox because Roomote launches their process inside that workspace. Most MCP servers publish a JSON snippet in their docs. The add dialog's **Import from JSON** button accepts a pasted `mcpServers` snippet (or a bare @@ -27,7 +28,7 @@ Three kinds of servers are supported: ## How remote servers are reached Remote custom servers are never handed to the task sandbox directly. The -sandbox sees an authenticated Roomote proxy URL, and the proxy injects the +sandbox and Fast use an authenticated Roomote proxy, and the proxy injects the real credentials per request. This means: - Header values and OAuth tokens never appear in sandbox-readable diff --git a/apps/docs/integrations/index.mdx b/apps/docs/integrations/index.mdx index c4694e85e0..7e0446cf19 100644 --- a/apps/docs/integrations/index.mdx +++ b/apps/docs/integrations/index.mdx @@ -72,7 +72,7 @@ from [Personal Settings](/personal-settings). | | Read-only database access in Supabase | Enable first, then teammates link accounts | | | Shared memory across tasks and Fast sessions | Admin connection once | | | Deployments, logs, and domain availability | Admin connection once | -| | Voice calls with Roomote on Fast Sessions | Admin connection once | +| | Voice calls with Roomote on Fast Sessions | Admin connection once | | | Public X posts, users, trends, and news | Admin connection once | | | Paid external capabilities via Zero | Admin connection once | diff --git a/apps/docs/integrations/voice.mdx b/apps/docs/integrations/voice.mdx index 35054bdded..5e0cfdd62a 100644 --- a/apps/docs/integrations/voice.mdx +++ b/apps/docs/integrations/voice.mdx @@ -1,7 +1,7 @@ --- title: Voice description: Let your team talk to Roomote on a voice call. -icon: 'audio-lines' +icon: 'openai' --- Connect Voice when you want people to [talk to Roomote](/voice) on a call from diff --git a/apps/docs/logo/integrations/agentmail.svg b/apps/docs/logo/integrations/agentmail.svg index 5a462aa4a6..29cba51e61 100644 --- a/apps/docs/logo/integrations/agentmail.svg +++ b/apps/docs/logo/integrations/agentmail.svg @@ -1,14 +1,6 @@ - - - + + + + + diff --git a/apps/docs/logo/integrations/voice.svg b/apps/docs/logo/integrations/voice.svg deleted file mode 100644 index 1648229851..0000000000 --- a/apps/docs/logo/integrations/voice.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/apps/docs/models.mdx b/apps/docs/models.mdx index be2cae36a1..4a45b4f285 100644 --- a/apps/docs/models.mdx +++ b/apps/docs/models.mdx @@ -140,6 +140,14 @@ in **Available Models**, and assign it to a role or select it for a Session or task. Adding these routes does not change existing model defaults; access still depends on the connected provider account or plan. +**DeepSeek V4.1 Flash** is recommended through +[OpenRouter](/providers/inference/openrouter), +[Vercel AI Gateway](/providers/inference/vercel-ai-gateway), and +[OpenCode Go](/providers/inference/opencode-go). Roomote uses the provider's +matching route and no longer recommends the older V4 Flash 0731 model. Existing +defaults do not change automatically; enable V4.1 Flash and assign it to a role +when you want to use it. + ### Recommended default models Providers also carry recommended defaults for the model roles below — for diff --git a/apps/docs/snippets/integration-name.jsx b/apps/docs/snippets/integration-name.jsx index 99220c9dd9..aef60311e8 100644 --- a/apps/docs/snippets/integration-name.jsx +++ b/apps/docs/snippets/integration-name.jsx @@ -6,9 +6,9 @@ export function IntegrationName({ href, icon, name }) { box: '/logo/integrations/box.svg', azure: '/logo/integrations/azure.svg', granola: '/logo/integrations/granola.svg', + agentmail: '/logo/integrations/agentmail.svg', monday: '/logo/integrations/monday.svg', rippling: '/logo/integrations/rippling.svg', - voice: '/logo/integrations/voice.svg', }; const iconSrc = manualIcons[icon] ?? diff --git a/apps/docs/source-control.mdx b/apps/docs/source-control.mdx index d4ae065a3c..fac12615ba 100644 --- a/apps/docs/source-control.mdx +++ b/apps/docs/source-control.mdx @@ -40,6 +40,20 @@ After setup, verify that Roomote can: - clone the repository inside a task sandbox - push a branch or open a reviewable change when the task finishes +## Manage existing pull requests + +Roomote can act on an existing pull request or merge request when you identify +it by repository and number. Across supported providers, an agent can update its +title or description, retarget its base branch, close it without merging, and +reopen it later. These actions update the identified pull request; they do not +create a replacement or delete its source branch. + +Draft-state changes depend on what the provider exposes. GitHub supports moving +between draft and ready states, while another provider may apply the supported +fields and report that the draft transition was unavailable. Roomote reports +these provider gaps and partial results instead of claiming the whole update +failed or silently creating a new pull request. + ## Attribution on pull requests and commits Roomote keeps human-readable attribution inside private repositories. For diff --git a/apps/docs/voice.mdx b/apps/docs/voice.mdx index 24fe06d183..b824c3b975 100644 --- a/apps/docs/voice.mdx +++ b/apps/docs/voice.mdx @@ -1,6 +1,6 @@ --- title: Voice -icon: audio-lines +icon: openai description: Talk naturally with a Fast Session using GPT-Live. --- @@ -56,9 +56,9 @@ Session, so the timeline shows both the conversation and the work behind it. During a call the Fast Session returns its results to the voice rather than writing them as chat replies; Roomote then reports them in its own words, -keeping numbers, names, paths, and link labels exact. If a result cannot be -spoken, for example because the call drops, it is written to the transcript -as a normal reply so nothing is lost. Typed messages sent during a call are +keeping numbers, names, paths, and link labels exact. The exact Fast result stays +in the transcript as a collapsed **Reported result to voice** row, including when +the call drops or speech is interrupted. Typed messages sent during a call are answered in writing as usual. Each spoken request is cleaned up (filler words, false starts, and misheard diff --git a/apps/web/src/components/settings/ExperimentalSettings.tsx b/apps/web/src/components/settings/ExperimentalSettings.tsx deleted file mode 100644 index bf85a6c2fc..0000000000 --- a/apps/web/src/components/settings/ExperimentalSettings.tsx +++ /dev/null @@ -1,69 +0,0 @@ -'use client'; - -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; -import { toast } from 'sonner'; - -import { FlaskConical, Skeleton, Switch } from '@/components/system'; -import { useTRPC } from '@/trpc/client'; - -import { Section } from './Section'; -import type { ExperimentalSettings as ExperimentalSettingsData } from '@/trpc/commands/experimental-settings'; - -export function ExperimentalSettings() { - const trpc = useTRPC(); - const queryClient = useQueryClient(); - const queryKey = trpc.experimentalSettings.get.queryKey(); - const settingsQuery = useQuery(trpc.experimentalSettings.get.queryOptions()); - const updateMutation = useMutation( - trpc.experimentalSettings.setOpenCodeCodeMode.mutationOptions(), - ); - - const handleToggle = async (enabled: boolean) => { - const previous = settingsQuery.data; - queryClient.setQueryData(queryKey, { - openCodeCodeModeEnabled: enabled, - }); - - try { - const updated = await updateMutation.mutateAsync({ enabled }); - queryClient.setQueryData(queryKey, updated); - toast.success(`Code Mode ${enabled ? 'enabled' : 'disabled'}`); - } catch (error) { - queryClient.setQueryData(queryKey, previous); - toast.error( - error instanceof Error ? error.message : 'Failed to update Code Mode.', - ); - } - }; - - if (settingsQuery.isPending) { - return ; - } - - if (settingsQuery.isError || !settingsQuery.data) { - return ( -
- Failed to load experimental settings. -
- ); - } - - return ( -
-
- void handleToggle(checked === true)} - /> -
-

- Defer eligible tools and discover them when needed, reducing the - tool definitions sent with each request. -

-
-
-
- ); -} diff --git a/apps/web/src/components/settings/pages/ExperimentalSettingsPage.tsx b/apps/web/src/components/settings/pages/ExperimentalSettingsPage.tsx index f804970071..cb1c77bade 100644 --- a/apps/web/src/components/settings/pages/ExperimentalSettingsPage.tsx +++ b/apps/web/src/components/settings/pages/ExperimentalSettingsPage.tsx @@ -1,12 +1,11 @@ 'use client'; import { SettingsShell } from '@/components/settings/SettingsShell'; -import { ExperimentalSettings } from '@/components/settings/ExperimentalSettings'; export function ExperimentalSettingsPage() { return ( - + {null} ); } diff --git a/apps/web/src/components/settings/settings-navigation.test.ts b/apps/web/src/components/settings/settings-navigation.test.ts index 080d797a00..9c8e9d9006 100644 --- a/apps/web/src/components/settings/settings-navigation.test.ts +++ b/apps/web/src/components/settings/settings-navigation.test.ts @@ -3,9 +3,9 @@ import { describe, expect, it } from 'vitest'; import { getSettingsNavigationItem } from './settings-navigation'; describe('settings navigation', () => { - it('describes Experimental settings with active opt-in features', () => { + it('shows the empty state for Experimental settings', () => { expect(getSettingsNavigationItem('experimental')?.description).toBe( - 'Try opt-in features that may change while they are being evaluated.', + 'No experimental features at the moment. Check back soon.', ); }); }); diff --git a/apps/web/src/components/settings/settings-navigation.ts b/apps/web/src/components/settings/settings-navigation.ts index 160419ff70..a776c2946f 100644 --- a/apps/web/src/components/settings/settings-navigation.ts +++ b/apps/web/src/components/settings/settings-navigation.ts @@ -174,8 +174,7 @@ const SETTINGS_NAVIGATION_ITEMS: SettingsNavigationItem[] = [ id: 'experimental', label: 'Experimental', title: 'Experimental', - description: - 'Try opt-in features that may change while they are being evaluated.', + description: 'No experimental features at the moment. Check back soon.', href: SETTINGS_PATHS.experimental, icon: FlaskConical, adminOnly: true, diff --git a/apps/web/src/trpc/commands/experimental-settings/index.test.ts b/apps/web/src/trpc/commands/experimental-settings/index.test.ts deleted file mode 100644 index 7aa4bebbb5..0000000000 --- a/apps/web/src/trpc/commands/experimental-settings/index.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -const { findFirst, insert, values, onConflictDoUpdate } = vi.hoisted(() => ({ - findFirst: vi.fn(), - insert: vi.fn(), - values: vi.fn(), - onConflictDoUpdate: vi.fn(), -})); - -vi.mock('@roomote/db/server', () => ({ - db: { - query: { deploymentSettings: { findFirst } }, - insert, - }, - deploymentSettings: { id: 'deployment_settings.id' }, - eq: vi.fn(), -})); - -vi.mock('../setup/shared', () => ({ - assertAdmin: (auth: { isAdmin: boolean }) => { - if (!auth.isAdmin) throw new Error('Unauthorized'); - }, -})); - -import type { UserAuthSuccess } from '@/types'; - -import { - getExperimentalSettingsCommand, - setOpenCodeCodeModeCommand, -} from './index'; - -const adminAuth = { userId: 'admin', isAdmin: true } as UserAuthSuccess; -const memberAuth = { userId: 'member', isAdmin: false } as UserAuthSuccess; - -describe('experimental settings commands', () => { - beforeEach(() => { - vi.clearAllMocks(); - insert.mockReturnValue({ values }); - values.mockReturnValue({ onConflictDoUpdate }); - onConflictDoUpdate.mockResolvedValue(undefined); - }); - - it('defaults Code Mode off and reads a persisted opt-in', async () => { - findFirst.mockResolvedValueOnce(undefined).mockResolvedValueOnce({ - metadata: { opencode_code_mode: true }, - }); - - await expect(getExperimentalSettingsCommand(adminAuth)).resolves.toEqual({ - openCodeCodeModeEnabled: false, - }); - await expect(getExperimentalSettingsCommand(adminAuth)).resolves.toEqual({ - openCodeCodeModeEnabled: true, - }); - }); - - it('persists the validated boolean without dropping other metadata', async () => { - findFirst.mockResolvedValue({ metadata: { keep_me: 'value' } }); - - await expect( - setOpenCodeCodeModeCommand(adminAuth, { enabled: true }), - ).resolves.toEqual({ openCodeCodeModeEnabled: true }); - - expect(values).toHaveBeenCalledWith( - expect.objectContaining({ - id: 'default', - metadata: { keep_me: 'value', opencode_code_mode: true }, - }), - ); - expect(onConflictDoUpdate).toHaveBeenCalledWith( - expect.objectContaining({ - target: 'deployment_settings.id', - set: expect.objectContaining({ - metadata: { keep_me: 'value', opencode_code_mode: true }, - }), - }), - ); - }); - - it('rejects non-admin reads and writes', async () => { - await expect(getExperimentalSettingsCommand(memberAuth)).rejects.toThrow( - 'Unauthorized', - ); - await expect( - setOpenCodeCodeModeCommand(memberAuth, { enabled: true }), - ).rejects.toThrow('Unauthorized'); - expect(findFirst).not.toHaveBeenCalled(); - }); -}); diff --git a/apps/web/src/trpc/commands/experimental-settings/index.ts b/apps/web/src/trpc/commands/experimental-settings/index.ts deleted file mode 100644 index 82b0f4072f..0000000000 --- a/apps/web/src/trpc/commands/experimental-settings/index.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { db, deploymentSettings, eq } from '@roomote/db/server'; -import { - isOpenCodeCodeModeEnabledFromMetadata, - OPENCODE_CODE_MODE_METADATA_KEY, -} from '@roomote/feature-flags'; - -import type { UserAuthSuccess } from '@/types'; - -import { assertAdmin } from '../setup/shared'; - -const DEFAULT_DEPLOYMENT_ID = 'default'; - -export type ExperimentalSettings = { - openCodeCodeModeEnabled: boolean; -}; - -function normalizeMetadata(value: unknown): Record { - return value && typeof value === 'object' && !Array.isArray(value) - ? { ...(value as Record) } - : {}; -} - -export async function getExperimentalSettingsCommand( - auth: UserAuthSuccess, -): Promise { - assertAdmin(auth); - const settings = await db.query.deploymentSettings.findFirst({ - where: eq(deploymentSettings.id, DEFAULT_DEPLOYMENT_ID), - columns: { metadata: true }, - }); - - return { - openCodeCodeModeEnabled: isOpenCodeCodeModeEnabledFromMetadata( - settings?.metadata, - ), - }; -} - -export async function setOpenCodeCodeModeCommand( - auth: UserAuthSuccess, - input: { enabled: boolean }, -): Promise { - assertAdmin(auth); - const existing = await db.query.deploymentSettings.findFirst({ - where: eq(deploymentSettings.id, DEFAULT_DEPLOYMENT_ID), - columns: { metadata: true }, - }); - const metadata = { - ...normalizeMetadata(existing?.metadata), - [OPENCODE_CODE_MODE_METADATA_KEY]: input.enabled, - }; - const now = new Date(); - - await db - .insert(deploymentSettings) - .values({ id: DEFAULT_DEPLOYMENT_ID, metadata, updatedAt: now }) - .onConflictDoUpdate({ - target: deploymentSettings.id, - set: { metadata, updatedAt: now }, - }); - - return { openCodeCodeModeEnabled: input.enabled }; -} diff --git a/apps/web/src/trpc/routers/_app.ts b/apps/web/src/trpc/routers/_app.ts index 02503631a8..3d34bec948 100644 --- a/apps/web/src/trpc/routers/_app.ts +++ b/apps/web/src/trpc/routers/_app.ts @@ -480,10 +480,6 @@ import { setDeploymentTimeZoneCommand, setAnonymousAnalyticsCommand, } from '../commands/misc-settings'; -import { - getExperimentalSettingsCommand, - setOpenCodeCodeModeCommand, -} from '../commands/experimental-settings'; import { backfillBrainTaskMemoriesCommand, getBrainPageCommand, @@ -3352,17 +3348,6 @@ export const appRouter = createRouter({ ), }), - experimentalSettings: createRouter({ - get: protectedProcedure.query(({ ctx: { auth } }) => - getExperimentalSettingsCommand(auth), - ), - setOpenCodeCodeMode: protectedProcedure - .input(z.object({ enabled: z.boolean() })) - .mutation(({ ctx: { auth }, input }) => - setOpenCodeCodeModeCommand(auth, input), - ), - }), - releases: createRouter({ status: protectedProcedure.query(({ ctx: { auth } }) => getReleaseStatusCommand(auth), diff --git a/package.json b/package.json index 1167a1d647..2595035aab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "roomote", - "version": "1.6.0", + "version": "1.7.0", "license": "FCL-1.0-ALv2", "packageManager": "pnpm@10.29.3", "engines": { diff --git a/packages/db/package.json b/packages/db/package.json index f8d1c5c91d..9948b8807c 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -40,7 +40,6 @@ }, "dependencies": { "@roomote/env": "workspace:^", - "@roomote/feature-flags": "workspace:^", "@roomote/types": "workspace:^", "drizzle-orm": "^0.45.2", "nanoid": "^5.1.16", diff --git a/packages/db/src/lib/model-runtime-config.test.ts b/packages/db/src/lib/model-runtime-config.test.ts index c42da2e30a..d6b2263551 100644 --- a/packages/db/src/lib/model-runtime-config.test.ts +++ b/packages/db/src/lib/model-runtime-config.test.ts @@ -98,46 +98,6 @@ describe('resolveEffectiveModelRuntimeEnv', () => { mockGetFreshXaiAccessToken.mockResolvedValue(null); }); - it('enables only the direct OpenCode Code Mode experiment when configured', async () => { - mockDeploymentSettingsFindFirst.mockResolvedValue({ - metadata: { opencode_code_mode: true }, - runtimeModelConfig: {}, - taskModelSettings: {}, - }); - - const [controlPlaneEnv, sandboxEnv] = await Promise.all([ - resolveEffectiveModelRuntimeEnv({ - runtimeEnv: {}, - deploymentEnvVars: {}, - }), - resolveSandboxModelRuntimeEnv({ - runtimeEnv: {}, - deploymentEnvVars: {}, - }), - ]); - - for (const env of [controlPlaneEnv, sandboxEnv]) { - expect(env.OPENCODE_EXPERIMENTAL_CODE_MODE).toBe('1'); - expect(env.OPENCODE_EXPERIMENTAL).toBeUndefined(); - } - }); - - it('leaves OpenCode Code Mode disabled by default', async () => { - mockDeploymentSettingsFindFirst.mockResolvedValue({ - metadata: {}, - runtimeModelConfig: {}, - taskModelSettings: {}, - }); - - const env = await resolveSandboxModelRuntimeEnv({ - runtimeEnv: {}, - deploymentEnvVars: {}, - }); - - expect(env.OPENCODE_EXPERIMENTAL_CODE_MODE).toBeUndefined(); - expect(env.OPENCODE_EXPERIMENTAL).toBeUndefined(); - }); - it('prefers real runtime env values over persisted deployment config', async () => { mockDeploymentSettingsFindFirst.mockResolvedValue({ runtimeModelConfig: { diff --git a/packages/db/src/lib/model-runtime-config.ts b/packages/db/src/lib/model-runtime-config.ts index 5aa6be76e2..1a5177cc10 100644 --- a/packages/db/src/lib/model-runtime-config.ts +++ b/packages/db/src/lib/model-runtime-config.ts @@ -1,5 +1,4 @@ import { eq } from 'drizzle-orm'; -import { isOpenCodeCodeModeEnabledFromMetadata } from '@roomote/feature-flags'; import { applyImplicitLiteLlmModelPrefix, CHATGPT_FAST_MODE_ENV_VAR_NAME, @@ -113,7 +112,6 @@ async function loadPersistedRuntimeModelConfig( const deployment = await executor.query.deploymentSettings.findFirst({ where: eq(deploymentSettings.id, DEFAULT_DEPLOYMENT_ID), columns: { - metadata: true, runtimeModelConfig: true, taskModelSettings: true, }, @@ -126,9 +124,6 @@ async function loadPersistedRuntimeModelConfig( catalogModels: getTaskModelCatalog(deployment?.taskModelSettings), enabledCatalogModels: getEnabledTaskModels(deployment?.taskModelSettings), defaultModelId: getDefaultTaskModelId(deployment?.taskModelSettings), - openCodeCodeModeEnabled: isOpenCodeCodeModeEnabledFromMetadata( - deployment?.metadata, - ), }; } @@ -413,13 +408,7 @@ async function resolveModelRuntimeEnv( const executor = options.executor ?? db; const [ persistedEnvVars, - { - runtimeModelConfig, - catalogModels, - enabledCatalogModels, - defaultModelId, - openCodeCodeModeEnabled, - }, + { runtimeModelConfig, catalogModels, enabledCatalogModels, defaultModelId }, ] = await Promise.all([ resolveEffectiveDeploymentEnvVars({ deploymentEnvVars: options.deploymentEnvVars, @@ -714,9 +703,6 @@ async function resolveModelRuntimeEnv( return { ...resolvedRoleEnv, - ...(openCodeCodeModeEnabled - ? { OPENCODE_EXPERIMENTAL_CODE_MODE: '1' } - : {}), ...(providerKeyNames.length > 0 && { R_MODEL_ENV_KEYS: providerKeyNames.join(','), }), diff --git a/packages/feature-flags/src/__tests__/config.test.ts b/packages/feature-flags/src/__tests__/config.test.ts index 70eacd5ea6..3e6733b0d8 100644 --- a/packages/feature-flags/src/__tests__/config.test.ts +++ b/packages/feature-flags/src/__tests__/config.test.ts @@ -3,14 +3,15 @@ import { describe, expect, it } from 'vitest'; import { DEPLOYMENT_METADATA_BOOLEAN_CONFIG } from '../config'; describe('deployment metadata config', () => { - it('retains active metadata descriptors', () => { + it('retains the deployment-control metadata descriptors', () => { expect(Object.keys(DEPLOYMENT_METADATA_BOOLEAN_CONFIG).sort()).toEqual([ 'anonymous_analytics_enabled', 'deployment_disabled', - 'opencode_code_mode', ]); - expect(DEPLOYMENT_METADATA_BOOLEAN_CONFIG.opencode_code_mode?.kind).toBe( - 'experimental', - ); + for (const descriptor of Object.values( + DEPLOYMENT_METADATA_BOOLEAN_CONFIG, + )) { + expect(descriptor.kind).toBe('deployment-control'); + } }); }); diff --git a/packages/feature-flags/src/__tests__/metadata-descriptions.test.ts b/packages/feature-flags/src/__tests__/metadata-descriptions.test.ts index e83f44b114..f2569fb1b3 100644 --- a/packages/feature-flags/src/__tests__/metadata-descriptions.test.ts +++ b/packages/feature-flags/src/__tests__/metadata-descriptions.test.ts @@ -11,6 +11,7 @@ describe('metadata descriptions', () => { 'visual_proof_auto_screencast', 'background_subagents', 'opencode_background_subagents', + 'opencode_code_mode', 'composerSuggestions', ])('classifies removed experiment metadata %s as legacy', (key) => { expect(getBooleanMetadataDescriptorByKey(key)).toEqual({ @@ -20,15 +21,6 @@ describe('metadata descriptions', () => { }); }); - it('classifies Code Mode as an active experiment', () => { - expect(getBooleanMetadataDescriptorByKey('opencode_code_mode')).toEqual({ - kind: 'experimental', - description: - 'Defer eligible tools and discover them when needed, reducing the tool definitions sent with each request.', - group: 'Code Mode', - }); - }); - it('retains active deployment-control descriptors', () => { expect(getBooleanMetadataDescriptorByKey('deployment_disabled').kind).toBe( 'deployment-control', diff --git a/packages/feature-flags/src/config.ts b/packages/feature-flags/src/config.ts index 30155cefb0..c573741edb 100644 --- a/packages/feature-flags/src/config.ts +++ b/packages/feature-flags/src/config.ts @@ -20,10 +20,4 @@ export const DEPLOYMENT_METADATA_BOOLEAN_CONFIG: Record< description: 'Share anonymous usage analytics (instance and user activity identified only by random IDs) with the Roomote team. Enabled by default; absent means enabled.', }, - opencode_code_mode: { - kind: 'experimental', - group: 'Code Mode', - description: - 'Defer eligible tools and discover them when needed, reducing the tool definitions sent with each request.', - }, }; diff --git a/packages/feature-flags/src/index.ts b/packages/feature-flags/src/index.ts index 41b3ddbdcb..80179ad6da 100644 --- a/packages/feature-flags/src/index.ts +++ b/packages/feature-flags/src/index.ts @@ -32,8 +32,6 @@ export function getBooleanMetadataDescriptorByKey( export const ANONYMOUS_ANALYTICS_METADATA_KEY = 'anonymous_analytics_enabled' as const; -export const OPENCODE_CODE_MODE_METADATA_KEY = 'opencode_code_mode' as const; - export function isAnonymousAnalyticsEnabledFromMetadata( metadata: unknown, cloudEnabled = false, @@ -45,10 +43,3 @@ export function isAnonymousAnalyticsEnabledFromMetadata( return coerceToBoolean(normalizedMetadata[ANONYMOUS_ANALYTICS_METADATA_KEY]); } - -export function isOpenCodeCodeModeEnabledFromMetadata( - metadata: unknown, -): boolean { - const normalizedMetadata = normalizeMetadataRecord(metadata); - return coerceToBoolean(normalizedMetadata[OPENCODE_CODE_MODE_METADATA_KEY]); -} diff --git a/packages/feature-flags/src/types.ts b/packages/feature-flags/src/types.ts index 221040fa75..d3101c3850 100644 --- a/packages/feature-flags/src/types.ts +++ b/packages/feature-flags/src/types.ts @@ -1,7 +1,4 @@ -export type MetadataBooleanKind = - | 'deployment-control' - | 'experimental' - | 'legacy'; +export type MetadataBooleanKind = 'deployment-control' | 'legacy'; export interface MetadataBooleanDescriptor { description: string | null; @@ -13,6 +10,5 @@ export interface MetadataRecord { queue_parallel_task_limit?: boolean | number | string; deployment_disabled?: boolean; anonymous_analytics_enabled?: boolean; - opencode_code_mode?: boolean; [key: string]: unknown; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7f6300b4c8..43bca2f2aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1343,9 +1343,6 @@ importers: '@roomote/env': specifier: workspace:^ version: link:../env - '@roomote/feature-flags': - specifier: workspace:^ - version: link:../feature-flags '@roomote/types': specifier: workspace:^ version: link:../types From 789c2d02614d828463300ac016c2ef7614b04126 Mon Sep 17 00:00:00 2001 From: "@mrubens" <2600+mrubens@users.noreply.github.com> Date: Fri, 11 Sep 2026 00:24:12 +0000 Subject: [PATCH 2/4] docs: correct Cost Analytics drilldown guidance --- apps/docs/cost-analytics.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/docs/cost-analytics.mdx b/apps/docs/cost-analytics.mdx index 3af23ed69a..4cf4475789 100644 --- a/apps/docs/cost-analytics.mdx +++ b/apps/docs/cost-analytics.mdx @@ -37,8 +37,8 @@ window. The chart overlays a **Total tokens** trend line on the cost bars. Its tooltip shows token and cost totals for the same day and grouping. The breakdown table -includes **Total tokens** and **Avg tokens / task** alongside cost, and selecting -a chart segment or table value opens the matching token-aware detail rows. +includes **Total tokens** and **Avg tokens / task** alongside cost. Selecting a +chart segment opens the matching token-aware detail rows. Analytics date presets and daily chart buckets use the web server's timezone, including daylight-saving transitions. Costs, Tasks, and PR analytics use the From 42d45ec965cf90df2576d14206af8b249d946b53 Mon Sep 17 00:00:00 2001 From: "@mrubens" <2600+mrubens@users.noreply.github.com> Date: Fri, 11 Sep 2026 12:16:56 +0000 Subject: [PATCH 3/4] chore: refresh Roomote 1.7.0 release --- .changeset/guide-select-focus-handoffs.md | 5 ----- CHANGELOG.md | 12 +++++++----- apps/docs/integrations/voice.mdx | 3 ++- 3 files changed, 9 insertions(+), 11 deletions(-) delete mode 100644 .changeset/guide-select-focus-handoffs.md diff --git a/.changeset/guide-select-focus-handoffs.md b/.changeset/guide-select-focus-handoffs.md deleted file mode 100644 index 08af8ca039..0000000000 --- a/.changeset/guide-select-focus-handoffs.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@roomote/web": patch ---- - -Move focus into required follow-up fields and dependent selectors after committed choices in guided setup flows. diff --git a/CHANGELOG.md b/CHANGELOG.md index 155ca5bd47..d7a78ac084 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,22 +8,22 @@ Roomote 1.7 adds natural voice and email conversations, smarter follow-through f ### Highlights -- Talk with Fast Sessions through GPT-Live voice calls, or start and continue Roomote work and private automation reports over email with AgentMail. +- Talk with Fast Sessions through configurable GPT-Live voices and previews, or continue Roomote work and private automation reports over email with AgentMail. - Let Fast quietly follow delegated coding tasks, surface meaningful developments, and correct work that drifts from the request. - Add natural-language routing rules to built-in automations and manage existing pull requests across supported providers. - Track token usage alongside spend in Cost Analytics, including historical totals when tasks are deleted. ### Minor changes -- Use Email through AgentMail as a replyable Roomote channel for task requests and custom automation reports, with inbox-scoped setup, durable threads, signed answers, verified-account safeguards, and verification status and resend controls in Linked Accounts. +- Use Email through AgentMail as a replyable Roomote channel for task requests and outcome-first custom automation reports, with inbox-scoped setup, durable threads, signed answers, verified-account safeguards, and verification status and resend controls in Linked Accounts. - Built-in automations can use natural-language Additional rules for repository scope, per-repository routing, and report guidance. - Track token usage alongside spend in Cost Analytics with a total-token trend line, provider and model totals and averages, and token-aware drilldowns. - DeepSeek V4.1 Flash replaces the dated Flash recommendation across OpenRouter, Vercel AI Gateway, and OpenCode Go. -- Fast Sessions quietly follow launched coding tasks, report meaningful developments, and apply evidence-backed corrections until the work settles. +- Fast Sessions quietly follow launched coding tasks, report meaningful developments, apply evidence-backed corrections until work settles, and distinguish task-history checks from incoming task reports. - Agents can close, reopen, retarget, and edit existing pull requests across supported source-control providers without creating replacements. - Weekly Manager Stats includes a daily created-versus-merged pull request chart and starts enabled on new deployments once a destination is configured. - Unify shared and environment-specific skills in one searchable Settings catalog with availability filters and a marketplace dialog. -- Talk naturally with Roomote from Fast Sessions, with GPT-Live handling full-duplex audio, live transcription, and interruptions while Fast handles every utterance with the Session's model, tools, and context. +- Talk naturally with Roomote from Fast Sessions, with deployment-wide voice selection and previews while GPT-Live handles audio and Fast handles every utterance with the Session's model, tools, and context. ### Patch changes @@ -35,8 +35,9 @@ Roomote 1.7 adds natural voice and email conversations, smarter follow-through f - Fast Sessions honor saved Routing Rules when selecting an environment or delegated coding-task model. - Source-control and Linear webhook redeliveries no longer risk repeating actions when the original audit outcome was not finalized. - Route every voice utterance through Fast so product answers use the Session's tools, context, and safeguards instead of unverified direct voice output. +- Move focus into required follow-up fields and dependent selectors after committed choices in guided setup flows. - Blank slate tasks no longer expose internal repository sentinels in task headers and filters. -- Independent Slack suggested tasks start in separate execution threads and Sessions instead of sharing task context. +- Independent Slack suggested tasks reliably start in separate execution threads and Sessions instead of sharing task context; rejected launches clean up misleading start messages and remain available to retry. - Communication replies use compact live footers that keep running-task counts, pull request links, and Session links current as work starts and finishes. - Preview Markdown artifacts directly in task and Session galleries before opening them. - Coding tasks recover from exhausted transient OpenCode connection resets instead of stopping without a useful Session handoff. @@ -51,6 +52,7 @@ Roomote 1.7 adds natural voice and email conversations, smarter follow-through f - Session timer activity uses user-facing labels instead of exposing internal wakeup tool names. - Automatic task follow-through timers stay out of the Session reminder list while user-created timer receipts clearly describe each action and reused schedule. - The Automations list combines built-in and custom entries with consistent search, columns, responsive text, and alphabetical ordering. +- Voice transcripts no longer show pending spoken acknowledgements after a call ends when the associated request was never sent. ## 1.6.0 (2026-09-09) diff --git a/apps/docs/integrations/voice.mdx b/apps/docs/integrations/voice.mdx index 88de15448a..22338b50a3 100644 --- a/apps/docs/integrations/voice.mdx +++ b/apps/docs/integrations/voice.mdx @@ -29,4 +29,5 @@ its WebRTC connection offer to Roomote and receives only the negotiated answer. Self-hosted operators can instead set `R_VOICE_OPENAI_API_KEY`. When both are present the environment variable is used. Roomote's general `OPENAI_API_KEY` is never used for voice, so enabling OpenAI for task inference does not turn -voice on. +voice on. An environment-managed connection is read-only in Settings and uses +Marin because it has no stored voice selection. From f080567b7693157123dd4800cfa662c6e66fa944 Mon Sep 17 00:00:00 2001 From: "@mrubens" <2600+mrubens@users.noreply.github.com> Date: Fri, 11 Sep 2026 12:22:20 +0000 Subject: [PATCH 4/4] chore: include latest Roomote 1.7.0 changes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7a78ac084..cdf7f22009 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ Roomote 1.7 adds natural voice and email conversations, smarter follow-through f - Open a user's Sessions directly from their avatar in Session viewers and task messages. - Session timer activity uses user-facing labels instead of exposing internal wakeup tool names. - Automatic task follow-through timers stay out of the Session reminder list while user-created timer receipts clearly describe each action and reused schedule. +- Automations and Skills page controls stay visible on desktop while long settings lists scroll independently. - The Automations list combines built-in and custom entries with consistent search, columns, responsive text, and alphabetical ordering. - Voice transcripts no longer show pending spoken acknowledgements after a call ends when the associated request was never sent.