Skip to content

The chat connects per workspace when shown, is a drawer in narrow windows, and lists sessions with /sessions - #671

Merged
danbarua merged 2 commits into
mainfrom
chat-sessions
Oct 12, 2026
Merged

danbarua merged 2 commits into
mainfrom
chat-sessions

Conversation

@danbarua

@danbarua danbarua commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

Problem

After #670, once the chat had been expanded on a page, every workspace visited opened a new session, even with the chat minimised. Going home and back opened another session in the same workspace. With the real agent, each of these was a saved session. In a window 860 px wide or narrower, the chat took its width from the page beside it. The only way to open an earlier session was the separate sessions page.

Change

When a session connects

  • A workspace's session connects the first time the chat is shown in that workspace. A workspace the chat is never shown in has no session.
  • Each workspace keeps its session for the life of the page. Leaving a workspace and coming back reopens the session it had (session/load) and names it in the address again, instead of starting another.
  • The chat's state moves into one hook, useChat (chat-sidebar.tsx). It holds the workspace's folder, which workspaces the chat has been shown in, and each workspace's session.

Narrow windows

  • In a window 860 px wide or narrower, the chat is a drawer over the page from the right, at most as wide as the window. Its button moves from the rail to the top bar, beside the theme button.
  • The rail and the border to drag are left out at that width.
  • The drawer uses the same scrim as the sidebar's drawer, and opening one drawer closes the other.

/sessions

  • In the Trace Console's chat, /sessions opens a palette of the sessions the agent keeps for the workspace's folder (ACP session/list by cwd).
  • The list is newest first, with each session's title, last update and id, and the open session marked. It is asked for each time the palette opens.
  • Picking a session reopens it and names it in the address.
  • The /agent page, which has no workspace, has no /sessions. The sessions list page stays, with no link to it.

Fixed in passing. A production build no longer asks the dev server for a workspace's folder. It answered 404, which the browser logged.

Controls

  • Session list ordering. A session the agent gives no time for goes last.
  • Narrow window drawer width. The drawer is as wide as the chat's saved width (400 px until its border is moved), or the window if that is narrower. On a phone it covers the page, and its button in the top bar closes it.
  • Server-side checks on a session's cwd are parked while the agent runtime is reworked.
  • Not seen in a browser by me this session; the layout at narrow widths in particular needs a look.

Verification

  • bun run check: exit 0, 1548 pass, 0 fail.
  • bun run e2e with E2E_PORT_API=9019 E2E_PORT_DEV=8970 E2E_PORT_BUILT=8971: 164 passed, 10 skipped (the dev-only tests, in the built bundle).
  • New e2e tests (dev server):
    • Opening alpha and following a link with the chat minimised sends no session/new or session/load. Expanding it sends one session/new. Minimising, going home and opening alpha again names the same session in the address and sends one session/load.
    • In a 600 px wide window, there is no right rail. The top bar's chat button opens the chat as a drawer in the viewport, and a click on the scrim beside it closes it.
    • /new starts a second session. /sessions opens a palette named "Sessions". Picking the first session reopens it, and the address names it.
  • Changed: the build's rail test passes again, because the build no longer fetches a folder.

Linked issues

None. This follows #670.

🤖 Generated with Claude Code

danbarua and others added 2 commits October 12, 2026 12:26
…rkspace's session, and is a drawer in narrow windows

- A workspace's session connects the first time the chat is shown in
  that workspace; visiting a workspace with the chat minimised opens
  none. Each workspace keeps its session for the life of the page, so
  leaving and coming back reopens it instead of starting another.
- In a window 860 px wide or narrower, the chat is a drawer over the
  page from the right, and its button is in the top bar. The rail and
  the border to drag are left out there.
- A production build asks the dev server for no workspace folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cking one reopens it

The agent is asked for its sessions in the workspace's folder (ACP
session/list by cwd) each time the palette opens, newest first, with the
open one marked. The /agent page, which has no workspace, has no
/sessions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the area:web The web app and shared UI: app-web, ui, design, records, view-model, acp-client label Oct 12, 2026
@danbarua
danbarua merged commit 177c84d into main Oct 12, 2026
10 checks passed
@danbarua
danbarua deleted the chat-sessions branch October 12, 2026 11:46
danbarua added a commit that referenced this pull request Oct 12, 2026
… reads (#672)

## Problem

The composer's `@` list was built but had nothing to list, and a mention
sent nothing to the agent but its text.

## Change

**Every file's path at HEAD, in the files API**
- `GET /workspace/{slug}/paths` answers the paths of the files in the
tree at HEAD, in name order, as a `paths` array. Directories and
submodules are not listed.
- At most 5,000 paths are listed. `total` counts them all, and
`truncated` says when some are left out.
- The top directory at HEAD links it as `paths`; a directory below the
top, and the tree at a commit, do not.

**Mentions in the chat**
- Once the chat has been shown in a workspace, it follows the
workspace's file collection to `paths` and offers each path after `@`.
- A file a message mentions is sent with it as a `resource_link`: `uri`
is `file://<workspace folder>/<path>`, each segment escaped, and `name`
is the path. The text block is sent unchanged.
- The mention parser (`mentionedLinks` in `src/ui/agent/mentions.ts`):
  - It links each file once, in the order first mentioned.
  - It tries longer paths first, so `@a.ts.bak` is not `@a.ts`.
  - It finds paths with spaces.
  - A full stop that ends a sentence also ends the mention.
  - An `@word` that names no file, or an `@` inside a word, stays text.

**ACP client.** `promptBlocks` and `SessionClient.prompt` take links.
The blocks go text, links, then attached files, and a prompt of links
alone has no text block. ACP requires every agent to take
`resource_link`, so no capability is checked.

## Controls

- **Link, not embedded content.** ACP prefers an embedded `resource`
when the agent takes embedded context, because it saves a round trip and
covers sources the agent cannot reach. Here the agent works in the same
folder, and embedding would mean the browser downloading the file from
the API and sending it back to the agent. The mention is a link the
agent reads itself.
- **How the agent treats the link.** The pinned labkit-effect host turns
a `resource_link` into a Markdown link line in the prompt's text
(`linesOf` in `host.ts`). In a test on :8850 against bonsai-2026, the
model saw `[README.md](file:///…/bonsai-2026/README.md)`, called it
"just markdown text", and offered to read it. Having the agent read
linked files in its folder is a change for the agent runtime, not this
repository.
- **HEAD only.** Mentions come from HEAD's tree, as the File Explorer
does. An uncommitted or ignored file cannot be mentioned. The agent
reads the file on disk, which may differ from HEAD.
- **A cut-short list** is used as it is, with a warning in the console
naming how many files were listed and how many there are.
- **The one address the page builds from data** is the `file:` URI. It
is an address for the agent, not an address of the API.
- **The paperclip.** It opens the file chooser in Chromium (checked with
Playwright's `filechooser` event). On the device used for the test
above, a click did nothing; this PR does not change it.

## Verification

- `bun run check`: exit 0, 1557 pass, 0 fail.
- `bun run e2e` with `E2E_PORT_API=9019 E2E_PORT_DEV=8970
E2E_PORT_BUILT=8971`: 165 passed, 11 skipped (the dev-only tests, in the
built bundle).
- **Unit tests:**
- `tests/git-api.test.ts`: the top directory links `paths`. The listing
has `README.md` and `src/a.ts`, no directories, and is in name order,
with `total` and `count` equal and `truncated` false. A lower directory
and the tree at a commit link no `paths`.
- `packages/acp-client/tests/prompt-blocks.test.ts`: a link is a
`resource_link` between the text and the attached files, whatever the
agent takes. A prompt of links alone has no text block.
- `tests/mentions.test.ts`: the `file:` URI escapes each segment. Each
mentioned file is linked once, in order. The longer path wins. A path
with a space and a sentence's full stop are handled. An unknown `@word`
and an `@` inside a word link nothing.
- **e2e, dev server:** typing `@README.m` offers `README.md`, and
picking it writes `@README.md `. Sending it posts `session/prompt` with
exactly the text block `look at @README.md` and one `resource_link` to
`file://<alpha's folder>/README.md`, named `README.md`.

## Linked issues

None. This follows #671.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:web The web app and shared UI: app-web, ui, design, records, view-model, acp-client

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant