Skip to content

Land the UX work: chart sources, search, calm computer start, waiting rows, app cards, owner apps, per-Bot files - #847

Merged
guidovizoso merged 91 commits into
mainfrom
guido/ux-integration
Oct 26, 2026
Merged

guidovizoso merged 91 commits into
mainfrom
guido/ux-integration

Conversation

@guidovizoso

@guidovizoso guidovizoso commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

What this changes

Everything from the seven UX PRs below, landed as one merge. Each PR's description has the detail, and they close when this merges.

Combining them needed two fixes:

CHANGELOG.md keeps every PR's entry.

Where it runs

See each PR.

Boundary and audit

See each PR.

Changelog

See each PR. "Before upgrading" in CHANGELOG.md covers the migrations and #846's move of a shared computer's files into a folder for each Bot.

Proof

Full CI on this branch. The same branch ran locally and was tested by hand: the search card, chart sources, the calm computer start, and the "Asking …" row with the Bot's avatar, including a refused address ending at once.

A chart now carries a basis (read, given, own knowledge), the sources it was
read from and an as-of date, and draws them under the plot. Figures the Bot
recalled without looking up are marked as unchecked. The model has to give a
basis; older conversations without one still render, with no footer.
Adds POST /api/plugins/for/:agentId/apps/:app/approve, admin only. It
files the request the app's state needs, as the admin, and approves it
straight away through the same code the inbox's Approve runs: the
approve body moved into a shared carryOut, and the filing checks into a
shared requestable, so the one press can't grant more or check less
than the two presses would.

The trail reads as the two presses: app_access.requested, then
app_access.approved marked direct. No refs, so only read-only actions
are granted, as the inbox does. A press that can't be carried out
withdraws the request it filed; one of the admin's own that was already
waiting is put back as it was.
… asked

A refusal is blocked by definition, but show_app_access also answers for
an app that is ready, and its card can't tell later whether the app
became ready since or was ready all along. The tool now writes
blocked: true or false from the state it found, so a card drawn already
ready can offer to carry on only where something actually changed.
Older answers without the field offer nothing.
An admin looking at an app that is off, or that a Bot wasn't given, now
gets one primary button: "Turn on and give it to <Bot>" or "Give it to
<Bot>". It calls the new one-press approve route, so the app is turned
on and its read-only actions granted with the same checks and trail as
the inbox. Send and write actions are still chosen on the Bot's page.

Where one press can't do it (no broker key, a set-up left unfinished, a
team account nobody connected) the admin gets a link to the app's admin
page in a new tab instead. The card reads the app again when its tab has
the focus back, so it follows whatever was done over there.
When the person finishes connecting in the other tab, or an admin turns
the app on and gives it to the Bot, the card used to say "Ask again and
the Bot can use it". Now the card that sees its app go from blocked to
ready sends one message on the person's behalf, "Gmail is ready now.
Please carry on.", through the same ask any transcript card uses.

Why a message and not handoff-resume: that resumes a browser tool call
that is still open. An app card is drawn from a call that already
answered, and its turn has ended, so there is nothing open to answer.
The next turn is what carries the task on. A visible message says why
the Bot started again, and the Bot gets the whole conversation with it.

Guards:
- Only while the card is the latest thing: the person has said nothing
  since it, has nothing queued, and the Bot isn't working. The
  transcript passes this down with the tool call id.
- Only once per card, across re-renders, remounts and tabs, by a mark in
  localStorage keyed by the tool call id, set before sending.
- Only automatically where the card saw the change. A card drawn already
  ready (an admin approved while the conversation was closed) offers a
  Continue button. For show_app_access it does so only if the marker
  says the app was blocked when the Bot asked.
holdsWebSearch reads the grant refs a built-in Bot is built with, and
researchRoleOfToolName reads the mcp__server__tool names a Bot running its
own loop is offered. Either counts a search tool from any research
provider, without needing its reader alongside.

RESEARCH_APP_NAMES lists the catalogue's search apps by title, the name
show_app_access resolves. There is no app called "search", so a Bot with
none has to name one, and listing every provider keeps the choice with
the administrator. A test holds the list to the catalogue's titles.
Asked to "search for" something in a demo, a Bot drove its browser to a
search engine. The computer guidance told it to navigate whenever asked
to look at, check or read anything, and never to claim it cannot browse;
the one line saying a page is not a search read as a hedge beside them.

computerGuidance now takes what the run holds and says one thing:

- With a search tool, finding information goes to it, and the computer
  is for signing in, clicking through, filling in forms, or opening a
  page the person asked to see.
- Without one, the browser never goes to Google, Bing or DuckDuckGo to
  look something up. The Bot answers from what it knows, says it has not
  checked it, and calls show_app_access once with one of Parallel
  Search, Exa Search or Firecrawl so the person can ask for it.

"Never claim you cannot browse" is gone; opening a page the person names
is still something the Bot does.

Every path gets the right wording. Built-in Bots are worded in
builtInAgentConfiguration from the tools they are built with, so a
narrowed run follows what it was offered. agent-bot and agent-langgraph
work it out from the tool names each run offers them, which are the
only view they have of their grants.
The tool description repeated the old prompt's "look at, visit, open or
check a website", which reads "check the latest on X" as a page to open.
It now says to open a particular site and never a search engine, so the
tool list agrees with the guidance beside it.
The busy signal said only that something was running, on the socket and
nowhere else. Read what a conversation waits on from the rows that
already say so: an unfinished hop it asked, folded with its relay, and
an open routine run. The channel read and the roster carry the list, and
every busy event carries the whole list at the moment it is sent.
…moves

The delivery's busy signal fires inside the run, while the row still
says the hop is in flight, so it cannot be what says the hop is over.
The runner now settles after finish or release, with the relay already
queued, and the desk announces a hop the moment it is offered.
Signalled around the firing and cleared after the run row has its
outcome, since the open run row is what the conversation reads.
…el's read

Busy events now carry the whole work list. It replaces the row's list in
the roster and the channel read the conversation screen uses, and both
are refetched with the roster after a reconnect or a resync. The sidebar
stays lit while a hop or a routine is pending between turns.
…e answer will land

"Asking Ana… 0:12" for a Bot its Bot asked, "Ana is running a routine…"
for a routine, at the end of the transcript, from the server's list.
Hidden while this tab's own turn runs. ProgressRow is the reusable line
for later waits.
…guido/ux-integration

# Conflicts:
#	CHANGELOG.md
… guido/ux-integration

# Conflicts:
#	CHANGELOG.md
…guido/ux-integration

# Conflicts:
#	CHANGELOG.md
…do/ux-integration

# Conflicts:
#	CHANGELOG.md
#	server/drizzle/meta/0064_snapshot.json
@guidovizoso guidovizoso changed the title Do not merge: CI for #840 to #846 together Land the UX work: chart sources, search, calm computer start, waiting rows, app cards, owner apps, per-Bot files Oct 26, 2026
@guidovizoso
guidovizoso marked this pull request as ready for review October 26, 2026 19:42
@guidovizoso
guidovizoso merged commit 3592f85 into main Oct 26, 2026
19 checks passed
@guidovizoso
guidovizoso deleted the guido/ux-integration branch October 26, 2026 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant