Phase 4: BYO-model bots + composer + invocation
Browser-direct model calls via Vercel AI SDK. Per-device multi-provider
keystore. Bot data model in CRDT. Composer with @-mention parsing.
Invoke flow: @bot in message → that bot replies, billed to @pinger's
key, streamed into the CRDT, broadcast to peers.
- src/lib/keystore.ts: per-device IndexedDB store for provider keys
(anthropic / openai / google / openai-compatible URL + optional key).
No server involvement. Shared 'hezo' IndexedDB with the CRDT store,
separate object store.
- src/lib/providers.ts: thin Vercel AI SDK wrapper. modelFor(bot, keys)
returns a LanguageModel for streamText. Anthropic uses the
dangerous-direct-browser-access header. MissingKeyError surfaces a
friendlier message to the UI than a raw 401.
- src/lib/crdt.ts: extended ProjectDoc with bots, conversations, turns.
loadDoc backfills missing top-level keys for forward-compat with
Phase 3 docs. New selectors: botList / conversationList /
turnsInConversation / findBotByName.
- src/lib/store.ts: new mutators for bots, conversations, turns.
beginBotTurn / updateTurnText / completeTurn / errorTurn drive a
streaming assistant turn. invokeBot runs streamText, accumulates
chunks, writes through updateTurnText (broadcast throttled to
~400ms so peers don't see every keystroke-equivalent).
- src/App.tsx: full rewrite of ProjectView into a sidebar + main pane.
Sidebar shows members, bots (with key-status warning), and
conversations. Main pane is a flat turn list + composer. Composer
parses @mentions, appends a user turn, fans out to matched bots in
parallel. Settings modal manages provider keys. Per-turn header shows
'@botname' or the human's email handle + timestamp + status.
New deps: ai, @ai-sdk/anthropic, @ai-sdk/openai, @ai-sdk/google,
@ai-sdk/openai-compatible, zod (for future tool defs).
Web + server typecheck clean. Vite build clean (1.28MB JS, gz 261KB —
provider SDKs + Automerge make up most of it). Live invocation flow
not yet smoke-tested in a real browser.