Skip to content

Add bot mode functionality - #81

Merged
milisp merged 7 commits into
masterfrom
feat/bot-mode
Sep 7, 2026
Merged

Add bot mode functionality#81
milisp merged 7 commits into
masterfrom
feat/bot-mode

Conversation

@milisp

@milisp milisp commented Sep 7, 2026

Copy link
Copy Markdown
Owner

This PR adds bot mode functionality to the Codexia desktop application, including:

  • A sidebar that lists existing sessions and allows starting a new one directly from the sidebar.
  • A sidebar trigger and drag‑drop workspace functionality added to the chat header.
  • A Tauri file dialog to pick a workspace folder.
  • Per‑bot conversation isolation, ensuring each bot keeps its own conversation history.
  • Provider and model selection via the ACP menu.
  • A settings dialog that opens automatically after creating a new bot.
  • A new Bot tab displaying keke‑backed chats.

The implementation consists of 7 commits that extend the codebase to support bot‑oriented interactions, improving usability and organization of chat sessions.

milisp and others added 7 commits September 7, 2026 07:34
A bot is a named, long-lived agent you keep messaging, listed the way a
messages app lists conversations. Each bot owns its own keke process, its
own workspace, persona, provider/model and trust level; the sidebar list is
deliberately cold, so a process only starts when you open a bot, and stays
up so coming back to one costs nothing.

Settings read the live agent where they can — provider and model come from
the running session's own lists once a bot has been opened, and are typed in
by hand before that.

keke's absence is handled where the user is looking: the composer is
replaced by an inline prompt with an Install button that runs
`npm install -g @milisp/keke` and re-resolves the presets, instead of a
toast. That needs a def to distinguish "installed" from "runnable": every
preset has an `npx -y <package>@latest` fallback, so with Node on PATH every
npm-published agent reports `available`. Defs now also carry `local` — the
agent's own binary resolved — and the Bot tab keys off that, while the ACP
chat pane keeps using `available`, where running through npx is a deliberate
offer rather than an accident.

Two smaller things the Bot tab needs to behave:

- `useAcpAgents` returns null until the list has resolved, so a first render
  cannot mistake "still loading" for "nothing installed".
- The composer reads liveness off this bot's own connection and session
  rather than the global ACP store, which can hold the chat pane's
  connection to a different agent — a stale one there neither hides the
  install prompt nor receives a bot's message.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PF1yKf8CW1SEePDThwVQrr
Jumping straight to the chat left a fresh bot on default name/model/
persona with no prompt to configure it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018bv61EeuSvQgLWBj8BcG4t
The bot settings dialog had grown a second, hand-rolled provider/model
picker, and only offered it while that bot's own connection happened to be
the live one. Reuse the composer's menu instead:

- extract the presentation of AcpModelMenu into AcpChoiceMenu, leaving the
  live wiring (optimistic apply, revert on rejection, sign-in) behind; the
  choice helpers move to modelChoices.ts so the .tsx only exports a component
- cache what keke advertises in useBotOptionsStore, so a bot that has never
  run — a brand new one included — still gets a list
- split the dialog into BotIdentityFields / BotModelFields / BotTrustFields
  and useBotSettingsForm

A bot picks a provider, it does not sign in: the account row reads "Provider",
and both rows offer "keke's default" so a bot can go back to inheriting
~/.keke/config.toml instead of overriding it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PF1yKf8CW1SEePDThwVQrr
The Bot tab renders from the single ACP store, which holds one conversation
at a time. Four ways that leaked:

- Opening is async, so a bot switched away from mid-load replayed its
  transcript into the pane of the bot now on screen. Every store write after
  an await now checks the bot is still selected.
- A bot gets a fresh session on each app restart, so the newest stored
  session is regularly an empty one. Replay now shows the newest session
  that has updates, followed by the current session's own, sealed at the
  seam so the two turns do not merge into one bubble.
- Creating a bot never starts it, and nothing cleared the pane, so a new bot
  opened showing the previous bot's messages. `openBlank` clears it.
- `running` was global, so a turn in one bot showed another as typing, and
  finishing it cleared the wrong bot's state. It is now per bot.

Also show a shell tool call's command even once output arrives — `rawInput`
was only rendered when there was no content, which is never the case by the
time the command has run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PF1yKf8CW1SEePDThwVQrr
Dropping a folder (or file) onto the header sets the bot's cwd via the
Tauri drag-drop event, and the header shows the sidebar trigger when
the sidebar is collapsed while reserving space for macOS traffic
lights, matching AgentViewHeader. The drag region is applied
explicitly across the name/title area so the whole strip stays
draggable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PF1yKf8CW1SEePDThwVQrr
@milisp
milisp merged commit 2a11699 into master Sep 7, 2026
1 check passed
@milisp
milisp deleted the feat/bot-mode branch September 7, 2026 13:30
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