Let the reader choose Owliver's language, and stop the suggestion row going silent
Some checks failed
CI / check (pull_request) Failing after 5m8s

Two changes to the assistant panel.

THE LANGUAGE SELECTOR. An account setting in the header menu, not a property of
the conversation: somebody who reads in Spanish reads in Spanish on every page
and after every reload, and making it per-thread would ask them to set it again
each time the panel opened. Held in localStorage and outside React, so the
Owliver panel — a different subtree from the header — sees the change without a
provider spanning both, and a second tab picks it up.

A TAG is sent, never a sentence, and the field is omitted entirely when the
choice is English. The backend maps it onto a closed set
(internal/runtime/language.go holds the same list) and an unrecognised tag
answers in English. The panel therefore cannot write prompt text from here,
which is the point: the selected string SELECTS a directive rather than
becoming one.

THE SUGGESTION ROW. It appeared exactly once per conversation and was silent
after that, whatever was asked. Every chip ever SHOWN was banned permanently in
a set that only grew; the server keeps returning the top of the same small
catalogue, so by the second turn every suggestion was already in it, the filter
emptied the list, and an empty list draws no row.

Asked and offered are not the same thing. A question this thread actually PUT
is excluded for good — it has an answer on screen and offering to repeat it is
not a follow-up. A chip merely DISPLAYED and passed over is held back only from
the turn directly after it, which is enough to stop the row redrawing verbatim
under consecutive answers; beyond that it is offerable again, because ignoring
a suggestion is not the same as having covered it.

Verified: 1710/1710 skill-checks, a clean typecheck, build and lint.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 15:27:02 +05:30
parent 1ef0c6fc8a
commit 8ac4e1ee88
6 changed files with 304 additions and 14 deletions

View File

@@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from 'react';
import { Link, Outlet, useLocation, useNavigate } from 'react-router-dom';
import { motion } from 'framer-motion';
import {
Bell, ChevronDown, LayoutGrid, LogOut, Menu, Search, Settings, Shield,
Bell, ChevronDown, Globe, LayoutGrid, LogOut, Menu, Search, Settings, Shield,
} from 'lucide-react';
import { cn } from '@/lib/utils';
import { base44 } from '@/api/base44Client';
@@ -11,10 +11,13 @@ import { Avatar } from '@/components/ds/Avatar';
import { Badge } from '@/components/ui/badge';
import {
DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel,
DropdownMenuSeparator, DropdownMenuTrigger,
DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem,
DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent,
DropdownMenuSubTrigger, DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet';
import { AssistantPanel, AssistantPanelProvider } from '@/components/ai-assistant';
import { LANGUAGES, setLanguage, useLanguage } from '@/components/ai-assistant/language';
import { UiEditingProvider } from '@/components/ui-tree/UiEditingProvider';
import { pageKeyForRoute } from '@/lib/skills/registry';
import { endAdminSession } from '@/lib/admin/session';
@@ -164,6 +167,11 @@ export default function AdminLayout() {
const navigate = useNavigate();
const [menuOpen, setMenuOpen] = useState(false);
/* The account's language. Held outside React so the Owliver panel — a
different subtree entirely — sees the change without a provider spanning
both, and so a second tab picks it up. See ai-assistant/language. */
const language = useLanguage();
/* Shared cache rather than a local fetch, so saving the profile updates the
header avatar and account menu without a reload. */
const { data: user } = useCurrentUser();
@@ -289,6 +297,45 @@ export default function AdminLayout() {
<DropdownMenuItem onClick={() => navigate('/admin/workspace/agents')} className="cursor-pointer">
<LayoutGrid className="mr-2 h-4 w-4" /> Agent Registry
</DropdownMenuItem>
{/* Language.
A submenu rather than a row that navigates, because there
is nothing to navigate TO: the whole setting is one choice
from a closed list, and a page built to hold a single
radio group would be a page nobody returns to.
A radio group rather than two items, so the control states
what it is — one of these, exactly one selected — to a
screen reader and to the eye, without the menu having to
draw its own tick.
What it governs is Owliver's replies. Nothing else in the
product is generated text, so nothing else changes; the
row is in the account menu rather than in the panel
because it is a property of the account and outlives any
one conversation. */}
<DropdownMenuSub>
<DropdownMenuSubTrigger className="cursor-pointer">
<Globe className="mr-2 h-4 w-4" /> Language
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuRadioGroup value={language} onValueChange={setLanguage}>
{LANGUAGES.map((lang) => (
<DropdownMenuRadioItem
key={lang.tag}
value={lang.tag}
className="cursor-pointer"
>
{lang.label}
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={signOut}