indifferentketchup ff29b48e3a v1.13.7: stability bundle — usage capture + payload/UI sanitization
Five fixes for latent regressions surfaced during the v1.13.x.cosmetic
revert investigation. None alter schema or compaction; all cleanup
against the v1.13.1-A AI SDK migration's hidden surface.

(1) provider.ts — includeUsage: true on createOpenAICompatible.
@ai-sdk/openai-compatible defaults this false, omitting
stream_options.include_usage from the request body; llama-swap never
emitted the usage block, so result.usage.inputTokens/outputTokens
resolved undefined and tokens_used / ctx_used landed NULL in every
assistant row since v1.13.1-A. No historical backfill.

(2) MessageList.tsx — hasText = m.content.trim().length > 0.
AI SDK v6 streaming occasionally emits a leading "\n" text-delta on
tool-call-only turns; the literal newline passed length > 0 and
rendered an empty bubble + ActionRow between every tool call. Trim
catches it without changing semantics for genuine content.

(3) MessageBubble.tsx — same trim on hasContent for the no-tool-calls
path. Defensive symmetry with MessageList.flatten.

(4) payload.ts — buildMessagesPayload skips assistant rows with
status='failed' AND assistant rows with status='complete' + empty
content + no tool_calls. Without this, a trailing empty/failed
assistant + the next attempt's placeholder produced "Cannot have 2
or more assistant messages at the end of the list" rejections from
the OpenAI-compatible upstream after cap-hit + Continue.

(5) budget.ts — BUDGET_NO_AGENT 15 → 30. Every tool in ALL_TOOLS is
read-only today; the 15-cap was forward-looking for write tools that
haven't landed. No-agent mode now matches BUDGET_READ_ONLY.

47 LoC across 5 files. 190/190 server tests pass.

Verified live: new assistant turns populate StatsLine token data;
single-tool-call turns no longer render the stray empty-bubble +
ActionRow between tool calls; Continue after cap-hit no longer hits
the trailing-assistant API rejection.
2026-05-22 13:24:19 +00:00
2026-05-14 19:24:50 +00:00
2026-05-14 19:24:50 +00:00
2026-05-14 19:24:50 +00:00
2026-05-14 19:24:50 +00:00

boocode

Self-hosted single-user developer chat app. v1: chat only.

Stack

  • Node 20, Fastify, postgres (porsager/postgres), ws, zod
  • React 18, Vite, TypeScript, Tailwind v4, shadcn/ui
  • Postgres 16
  • pnpm workspaces

Layout

  • apps/server — Fastify API + WebSocket + inference loop + file-read tools
  • apps/web — React frontend; served by Fastify in production, Vite in dev

Local dev

Requires Node 20, pnpm, Docker (for Postgres), and ripgrep.

# install
pnpm install

# bring up postgres only
cp .env.example .env
# edit POSTGRES_PASSWORD if you like; default DATABASE_URL points at the container
docker compose up -d boocode_db

# run server (port 3000) and web (port 5173) in two shells
DATABASE_URL=postgres://boocode:devpass@127.0.0.1:5500/boocode \
LLAMA_SWAP_URL=http://100.101.41.16:8401 \
pnpm dev:server

pnpm dev:web

The Vite dev server proxies /api and /api/ws/* to the Fastify backend with a synthetic Remote-User: sam header so the Authelia auth layer can be skipped during development.

Production

cd /opt/boocode
docker compose up --build -d

Binds to 100.114.205.53:9500 (Tailscale). Authelia is expected to gate the upstream and inject Remote-User. Postgres binds loopback only.

What v1 has

Project sidebar, sessions per project, chat with streaming responses over WebSocket, four file-read tools scoped to the project root (view_file, list_dir, grep, find_files), and a model picker driven by llama-swap's /v1/models.

What v1 does not have lives in v2 (terminal pane) and v3 (Coder pane).

Description
No description provided
Readme AGPL-3.0 7.3 MiB
Languages
TypeScript 94.3%
CSS 1.9%
JavaScript 1.2%
Shell 0.8%
Go 0.6%
Other 1.2%