Skip to main content

Changelog

All notable changes to Brainstormer V2 are documented here. This project follows Semantic Versioning.

Unreleased

Shopify agents build again while Shopify rate-limits our servers

Building an agent from a Shopify store was failing with “Could not connect to your store” even for public stores with the right URL. Shopify had started rate-limiting product-catalog reads from our servers’ IP address, across every store at once, and the platform reported that as a problem with your store.
  • Catalog reads now get through a rate limit. When Shopify refuses our server, the catalog is fetched through a reader service with its own network instead, so products, prices and stock still index — including the scheduled stock sync.
  • Store stock is re-checked hourly instead of every 15 minutes. The interval is configurable per deployment (ECOMMERCE_INVENTORY_SYNC_MINUTES).
  • Errors say what actually happened. If the store cannot be reached even that way, the error now says Shopify is rate-limiting requests (503, store_throttled) and to try again in a few minutes, instead of suggesting the store is password-protected or the URL is wrong.
  • .myshopify.com addresses get a precise hint. Shopify refuses the .myshopify.com address of any store that has its own domain. Submitting one now tells you to use the store’s primary domain (for example https://www.allbirds.com).

Tools follow the model, and the data behind that is corrected

An agent’s tools are now matched against what its model can actually read, and the agent editor says so in plain language instead of leaving you to find out in a conversation.
  • A tool the model cannot run is marked unavailable, with the reason — for example “Needs image input — Llama 3.1 8B accepts text only” — on the agent’s Tools tab. It replaces a blanket “Requires function calling” label that was shown whatever the real reason was.
  • Nothing is switched off behind your back. Your setting for a tool is never changed when you change model. Pick a model that supports it again and the tool is simply working — there is nothing to turn back on.
  • Changing the model tells you what it costs first. Saving a model that cannot run one of your agent’s live tools asks you to confirm and lists them. You can still make the change; you just are not surprised by it.
  • The attachment button reflects the model. On a model that cannot read images, images are no longer offered and the control explains why. On one that cannot read attachments at all, it is switched off rather than accepting files the agent will never see.
  • The agent no longer guesses at its own limitations. When a file could not be read, the limitation used to be written into the message sent to the AI, which then told you something like “I don’t have access to view this image” — its best guess, not the fact. Limitations are now stated on the screen you are looking at.
  • Model capability data was wrong for most models, and is repaired. Of the 396 models available, 272 had a mis-parsed list of the input types they accept, and 52 that genuinely accept images were recorded as not accepting them — Claude Sonnet 4 among them. Every record has been corrected and the import can no longer produce the old value.
GET /api/bots/:id and the public agent endpoint now return modelInputModalities. See Get Agent.

Seats are checked when you invite, and every sign-in page looks the same

Settings → Team now shows how many of your plan’s seats are in use, for example 3 of 5 seats used (1 pending invitation). A pending invitation holds a seat until it is accepted or expires. When every seat is taken, the invite form is disabled and links to the upgrade page.
  • Seats are checked when an invitation is sent, for everyone who can invite, platform administrators included. Nobody receives an invitation they cannot accept.
  • Only owners and admins can invite, and an invitation can grant Admin, Member or Viewer — never Owner.
  • The login, sign-up, invitation, password reset and email verification pages all show the same logo and a new description of what Brainstormer does.
  • The seat-usage API now returns pendingInvitations. See Get Seat Usage.

Tool pages show what each tool tells your agent

On the Tools tab, a tool’s Configure page has a System prompt section card: the guidance that tool adds to your agent’s prompt. That card could show up empty. It now always shows something useful:
  • If the tool is on and saved, the editor opens straight onto that tool’s section. It is the same text as on the Prompt tab, so you can edit it in either place.
  • If you have turned the tool on but not saved the Tools tab yet, the card says so. A Save Tools button appears at the top of the tool’s page whenever the Tools tab has unsaved changes, so you can save without going back.
  • Tools with nothing to edit there, such as Voice Input, show no card.
Custom tools now have this card too. Open Custom Tools, choose Configure on a tool, and you can edit what that tool tells this agent.Saving a tool’s settings and then pressing Save Tools no longer resets those settings.

Replies appear as they are written

An agent’s reply now shows up word by word while it is being written, instead of appearing all at once when it finishes. The “thinking” indicator disappears as soon as the first words arrive.
  • The chat follows along as the answer grows. If you scroll up to re-read something, it leaves you there instead of jumping you back down.
  • Opening a link to a specific message no longer fights with a reply that is still being written.
Connecting a knowledge base to an agent, or disconnecting it, now requires edit access to both the knowledge base and the agent. Viewers without that access can no longer change which knowledge bases an agent uses, and a knowledge base can only be connected to an agent in the same organization. Each connect and disconnect is recorded in your organization’s audit log. See Link Agent to KB.

Creating an agent takes up to 3 sources

The Creator Wizard now accepts at most 3 sources when you create an agent. A source is one entry you add — a website, a YouTube or Instagram channel, a Shopify store or an uploaded file — not the individual posts or videos inside it, so a single channel can still supply many items to build from. Once you have added 3, the add controls turn off with a note saying why, and nothing is dropped silently. If you resume an agent that already has more than 3 sources attached, the wizard lists them all and asks you to remove the extras before it continues. Setup requests that send more than 3 sources are rejected with too_many_sources. Sources you add to an existing agent or knowledge base are not limited. See Creator Wizard and Agent provisioning.
  • The “not enough credits” message now reads “approximately 500 credits for AI setup of up to 3 sources”. The figure itself is unchanged.

Web & Embed: landing page, embed widget and brand in one place

Setting up your agent on the web used to take three screens: the Brand tab and two separate Distribute cards. They are now one Distribute → Web & Embed page with three sections — Landing Page, Embed Widget and Brand — each with its own Save button. Moving between sections keeps unsaved edits, and saving one section no longer risks undoing a change you just saved in another. Old links to the Brand tab open its new home.
  • “Visitor Questions” is now “Variables”. The tab explains both ways a value reaches your agent: collected from visitors by the form on the landing page and embed widget (a button takes you to it), or passed by your own code through the API. Use them in prompts as {{name}}. Values are not verified, so don’t use them for anything that must be trusted.
  • The welcome message says where it is used. It is sent at the start of every new conversation on every channel, WhatsApp included, and the editor now says so. Generated mode explains that it writes a new welcome for each conversation, costing one AI call in credits, and that there is no fixed text to edit.
See Web & Embed.
  • Linking is checked. When you create or edit an agent, every knowledge base you link must exist, belong to your organization, and be one you can edit. If one isn’t, nothing is saved and the agent editor tells you why.
  • Creating an agent needs the Member role or higher. Viewers can no longer create agents.
  • Creating a knowledge base needs the Member role or higher too. Viewers can still read the knowledge bases they have access to, but can’t create new ones.
  • Permissions are enforced the same way behind the scenes. When the platform works on your behalf between its own services, it now carries your role with it, so a Viewer is always treated as a Viewer.
  • Public and WhatsApp agents answer from their knowledge bases again. Conversations with no signed-in user had stopped drawing on an agent’s knowledge bases; they use them again.
  • Those conversations now use credits for knowledge search. Public widget, WhatsApp and WhatsApp Business conversations had been skipping the knowledge-base search, and so its cost, since the lookups were failing. Now that they search again, each turn is billed for the search and embedding work it does, and a file a visitor attaches is billed for reading it — to your organization, the same as a signed-in user’s conversation.
See Agents for the new 400 invalid_knowledge_base_ids and 403 responses, and Knowledge Bases for the new 403 on creating one.

Choose which knowledge bases to delete with an agent

Deleting an agent now shows exactly what goes away before you confirm — its public page and web widget, connected WhatsApp numbers (which stay connected but stop replying), and how many past conversations are kept. Every knowledge base linked to the agent is listed with its size, unticked by default, so you can delete the agent alone or take chosen knowledge bases with it. Knowledge bases another agent still uses, or that you can’t delete, are shown but can’t be ticked. If a knowledge base can’t be deleted the dialog says so and lets you retry just that one. Deleting a knowledge base on its own now lists the agents that lose access to it. See Deleting an Agent and Agent Delete Impact.

Small fixes: /newchat, wizard step badges, large source lists, image and audio uploads

  • /newchat works in WhatsApp. Typing /newchat now starts a fresh conversation, the same as /new, /clear and /reset.
  • Creator wizard step badges are accurate. Going back to an earlier step no longer un-checks the steps after it, and a step you skipped is no longer shown as done.
  • Adding more than 10 sources works. Websites and channels beyond the first ten are now read in batches instead of being dropped.
  • Image and audio files can be added to a knowledge base. Uploaded images are embedded and have any text in them extracted; audio is embedded and transcribed, using your knowledge base’s media setting.

Chat, preview and developer portal polish

  • Long links and ids wrap in chat replies. A very long URL or token in an assistant message now breaks inside the bubble instead of stretching it.
  • Cleaner agent preview. When a platform admin previews another organization’s agent, the blue banner above the message box is gone. The “Platform admin view” pill beside the agent name remains, and the page description now notes that preview messages are chargeable and to which organization.
  • Consistent status chips. The Draft / Live and “Platform admin view” chips on the agent chat page use the standard badge styles.
  • Quick Start base URL. The Developer page shows your own deployment’s API address (its origin plus /v1) rather than a fixed hostname.

Provision agents from a Shopify store or company website

The public Provision Agent from URL API (POST /v1/agents:from-url) now accepts a sourceType hint, so a pasted URL can be a Shopify store (sourceType: "shopify" — ingests the product catalog plus brand/site content) or a company website (sourceType: "website" — homepage and brand content), not just a YouTube/Instagram channel. Channel URLs still need no hint and are auto-detected. The caller’s frontend decides the source type; see Source types & detection. The store or website URL you submit is fetched through the SSRF guard, so an internal address is refused rather than fetched.

Sign in with Google, and switch organizations that actually switch

You can now sign in or sign up with Google, alongside email and password. The “Continue with Google” button appears once a platform administrator has entered a Google OAuth Client ID and Secret under Admin → System Config. If you sign in with Google using an email that already has a Brainstormer account, the two are linked automatically — provided Google has verified that email. Signed up with Google and later want a password too? Use “Forgot password” to set one; you can still continue with Google.The organization switcher in the sidebar now changes your active organization for real. Picking a different workspace re-scopes everything you do next to it, instead of quietly doing nothing.

Hardened the API gateway against path traversal

Requests to the API gateway can no longer use .. or encoded dot segments in the path to slip past a route’s authentication and reach an internal service endpoint. Any such path is now rejected. Every gateway proxy lane has also been audited to confirm it declares its authentication gate, with a test that keeps it that way.

Existing users can accept organization invitations

Someone who already has a Brainstormer account can now accept an invitation to another organization. Previously the invitation link showed them a sign-up form for an account they already had.
  • Not signed in: the invitation page explains that an account already exists and offers Log in to accept, which returns them to the invitation after logging in.
  • Signed in with the invited email: a confirmation card asks Join as ? — accepting adds the organization to their account; Not now leaves without joining.
  • Signed in with a different email: the page says the invitation was sent to another address and offers to log out and switch accounts.
  • Security: an invitation link can no longer be used to sign in to an existing account. Joining with an existing account now always requires logging in to that account first.
  • New-account passwords on the invitation page now require 8 characters, matching the server’s rule.

Knowledge base “visibility” removed

Knowledge bases no longer show a Private / Shared / Public visibility setting. That setting was only ever a label: it never changed who could open a knowledge base, so it has been removed rather than left looking like a privacy control.
  • Who can reach a knowledge base is unchanged: everyone in your organization with an owner, admin or member role, plus anyone given access to it directly.
  • The create form, the knowledge base list and the knowledge base header no longer show a visibility badge or picker.
  • API clients that still send visibility are not rejected; the field is ignored.

Delete a custom tool

Each custom API tool in the Custom Tools Hub now has a delete action. Deleting is permanent and cannot be undone — the tool is removed from the hub and from every agent in your organization that was using it, and the only way back is to set it up again from scratch.
  • Your agents, their conversations and your billing records are untouched.
  • Past runs of the tool stay in your usage history, but the tool’s own Activity view goes away with it.
  • The confirmation dialog names the tool and spells out what deleting it does before you commit.

Export contacts to CSV

The Contacts page now has an Export CSV button that downloads every matching contact — including the attributes your agents have collected — into a file that imports cleanly into other CRMs and outbound tools.
  • Exports whatever the current filters describe (search, channel, status, agent).
  • Streams the full result set with no row cap.
  • Includes a company, title, and every collected attribute as its own column, plus the contact’s organization name.
  • Available from the API as GET /api/contacts/export, and to developer keys as GET /v1/contacts/export with the contacts:read scope.

Cleaner analytics screens and model picker

Titles on the Analytics and knowledge base analytics pages no longer spill out of their boxes, and the stat tiles, date picker and export menu now share the same look as the rest of the platform, including on phones.In the model picker, the Input and Output price columns no longer run into each other. The confusing “1 / 0 conversations per month” note is now its own “Chats / month” column, reading ”≈ N” typical chats your plan covers each month (a typical chat is ten turns), or ”< 1” when your plan is too small for one, and ”—” for free models.

Your usage and analytics now speak credits, not dollars

Every place you see your usage — the Analytics page, a knowledge base’s cost breakdown, and the token count under an agent’s chat replies — now reports it the same way your balance does: in credits. Nothing changed about what’s billed or how much; the numbers on screen now match the one number on your Credits page.Analytics also now tells you when a handful of requests couldn’t be priced, instead of silently showing them as free.We also fixed a security gap: analytics requests were not being checked for who was asking, so it was possible to view another organization’s usage totals. That’s now locked down — every analytics request is verified and scoped to your own organization.

Your renewal date is now always correct

The “renews on” date on your Credits page is now calculated from your actual subscription (or the 1st of the month if you’re on the free plan), instead of an internal date that didn’t track your real billing cycle. Your available balance, the renewal date, and your add-on credits now read exactly the same on the Credits page, your Home dashboard, and Referrals — one number, everywhere.

Every credit transaction now explains itself

Your credit ledger entries used to show a raw internal label. They now read like a sentence — “Monthly plan renewal · Growth plan · 35,000 credits”, “Credit top-up · 10,000 credits” — so it’s clear what each entry was for, including for past transactions.

The upgrade page recognizes your current plan

The Upgrade page now shows your current plan clearly, and if you’re on a custom or enterprise plan, it no longer offers a self-serve “Upgrade” button that can’t actually change your plan — it shows a “Custom plan” badge and a “Contact us” button instead. The model picker now shows estimated credits per 1,000 tokens and roughly how many conversations a month that buys on your plan, instead of a raw dollar figure.

We now notice when Meta blocks your WhatsApp

A WhatsApp Business Account can be blocked by Meta from starting conversations — most often because a payment method needs attention — while everything on your side looks perfectly normal. The number is connected, the access token is valid, and customers simply stop getting answers. That happened to one account for ten days and nobody found out.Brainstormer now asks Meta directly, every 30 minutes, for every connected WhatsApp Business number:
  • Blocked — Meta refuses business-initiated messages. Replies inside an open 24-hour window may still go out; templates and first contact will not.
  • Limited — Meta has capped what the account may send, or cut the number’s quality rating or messaging tier.
  • Disconnected — the number is not serving, or the stored access needs renewing.
When a channel changes state, your organization’s owners and admins get one email: what Meta actually said, in Meta’s own words, and where the fix lives — which for a blocked account is Meta Business Manager, not the reconnect button here. One more email says so when it clears. Never one per check.A banner appears on every page while a channel is in trouble, the agent’s Channels tab explains it in place, and the agent row carries a status pill.You can turn these emails off per person under notification preferences.

And how many conversations your team has taken over

When a colleague replies from the WhatsApp Business app, or takes a conversation in the Inbox, the AI deliberately stops answering that thread — the customer is talking to a person now. Until now nothing showed you how many threads that applied to, so an agent could be quietly handling almost none of its live conversations.Each agent row now says “AI paused on N conversations”, in neutral styling, linking to the Inbox. It is information, not a fault.

The Conversations Inbox shows your conversations again

The Inbox spent most of a laptop screen on its own headings and filters: on a 1440x900 display barely one conversation row was visible before you had to scroll. Six or more now fit.The seven view chips (All, Unassigned, Mine, Assigned, AI handling, Approvals, Resolved) are back on a single row that scrolls, with a fade and arrow buttons at whichever edge has more views behind it — and the view you are on is always brought into sight. Channel, agent and workspace have moved behind one Filters button that shows how many you have applied; everything still comes back from a shared link exactly as before. The repeated “Inbox” heading above the list is gone, and the count of conversations in the current view now sits at the bottom of the list.Full screen. A new button in the Inbox toolbar hides the breadcrumb, the page header, the tabs and the sidebar, handing the whole window to your queue — about eight conversations at a glance. Press it again or hit Esc to come back, and your choice is remembered next time you open the Inbox.

Conversations module unifies operator and chat history

The Operator dashboard and Chat History are now one destination: Conversations in the sidebar. A single inbox shows live and resolved conversations with seven overlapping view chips (All, Unassigned, Mine, Assigned, AI handling, Approvals, Resolved). Navigate to Conversations → Inbox → Resolved chip to browse past conversations. The full message thread and all capabilities (search, rename, delete, export PDF) work across all states. Approvals are now a view within the Inbox, not a separate page, and resolution preserves the complete transcript for future review.Every conversation — live or escalated, awaiting approval, AI-handled or handed to a human — has one route: /conversations/[id]. Operator presence and working hours are configured in Settings. An approval is now reviewed in the conversation it belongs to: the customer’s question and the agent’s proposed reply are both on screen, and you can send it as written, edit it first, or reject it. All legacy operator and chat-history routes have been deleted outright, with no redirects — stale links were rewritten in the same change.

Organization filter sizes correctly on iPhone

A follow-up to yesterday’s fix. The filter stayed open with the keyboard up, but on iPhone it was still laid out as though the keyboard were not there — the search box was pushed above the top of the screen and the list ran on underneath the keyboard.The menu now measures the area you can actually see, so it always fits between the top of the screen and the keyboard, with the search box in view. On phones and tablets it also no longer grabs the keyboard the moment it opens — the list appears at full height and the keyboard comes up only when you tap the search box.

Organization filter now works on phones and tablets

On touch devices, opening the organization filter on Agents, Knowledge Bases, Chat History or Contacts closed it again immediately — the filter opens with the search box focused, which brings up the on-screen keyboard, and the menu treated that as a reason to dismiss itself. The filter was effectively unusable on mobile.The menu now stays open and re-anchors itself when the keyboard appears or the page scrolls, closing only when you pick an organization, tap outside, or press Escape. It also no longer opens past the top of the screen on short windows, and it shrinks to fit the space available instead of running off the edge.

Empty knowledge bases can be deleted again

Deleting a knowledge base that had never finished indexing a document failed with “Failed to delete knowledge base”. The vector store had nothing to remove for such a knowledge base and reported that as an error, which stopped the delete. That case is now treated as already clean and the delete completes.

Website crawls and URL syncs no longer stall

Website and URL sources could sit at “Pending” indefinitely, with no error shown. Our page renderer had asked us to wait several hours before retrying, and we waited — blocking every other site sync on the platform behind it.We now give up on a renderer that asks for an unreasonable wait and switch to a different one, and any sync that runs unusually long is ended and reported instead of blocking the queue.

Agents remember the options and products they have already shown

On WhatsApp, the tappable options and product cards an agent sent were not part of the conversation the AI reads back. On the next turn it had no record of them, so it could offer the same choices again or fail to understand “the second one”. The agent now sees what it previously showed, in the place it showed it — so a question, the options offered with it, and the customer’s answer read together.It only counts what actually reached the customer. When WhatsApp limits how many product cards can go out in one message, the ones that were not sent are left out rather than assumed — so the agent never discusses a piece the customer never saw.Nothing changes in the chat transcript you or your operators see.

WhatsApp messages now arrive in the order the agent sent them

On WhatsApp, a follow-up message could appear above the product carousel it referred to — most visibly the “What next?” options, which landed before the products they asked about. WhatsApp does not guarantee that messages arrive in the order they were sent, and a carousel takes longer to go out because WhatsApp has to fetch every product image first, so the smaller message overtook it.Each message now waits for WhatsApp to confirm the previous one was sent before going out. If that confirmation is slow or never arrives, the message is sent anyway, so nothing is ever lost.

Platform admins can search a knowledge base outside their own workspace

Searching a knowledge base belonging to another workspace returned “No matches found” for platform administrators, even when the knowledge base was fully indexed and every other tab on it — Documents, Sources, Graph — worked normally. Search now returns results, and the Search Log panel on that page lists them.

Switching workspace works on mobile again

On a phone, the workspace selector opened and closed again immediately, so there was no way to switch workspace. It now stays open until you pick one or tap away.

Platform admins can see an agent’s custom tools

An agent’s Custom Tools tab appeared empty to platform administrators viewing an agent outside their own workspace, even though the tools were configured and working. The tab now lists them, and enabling or disabling one works.

Credit top-ups are no longer lost if something goes wrong mid-purchase

If an error occurred in the moment between your card being charged and the credits being added, the purchase could complete without the credits ever arriving — and nothing recorded that they were owed.Payments are now retried automatically until the credits land, and a purchase that cannot be completed is surfaced rather than passing silently.

Requests to speak to a human now reach your operators

When a visitor on your website widget, WhatsApp, or any other channel asked to talk to a person, the request could fail without anyone being told. The conversation was not flagged as escalated, it never appeared on the operator dashboard, no notification went out — and after a few seconds the agent told the visitor that nobody was available.This affected visitors who were not signed in, which on most agents is nearly all of them. It is fixed: escalations from anonymous visitors now route, notify, and appear on the dashboard like any other.

Conversations that were escalated can now be deleted

Deleting a conversation failed with an error if it had ever been escalated to a human or sent for approval. Those conversations can now be deleted, along with their escalation history.

Large documents no longer drop out of the knowledge graph

Knowledge-graph extraction had a response-size limit that dense documents could exceed, and when they did, the entities and relationships for that section were discarded rather than saved. The limit has been raised.Documents already marked failed are not automatically re-processed — if a document is missing from your graph, re-upload it or contact support.

Your plan’s price and allowance are now fixed for as long as you stay on it

When we change what a plan costs or how many credits it includes, that change applies to new subscriptions only. Existing customers keep the price they signed up at — Stripe has always pinned that — and now keep their credit allowance and limits too.Previously the allowance was read from the live plan row, so repricing a tier would have quietly changed what current subscribers were shown and what they received at their next renewal, while their card was still charged the original amount. Every billing account now carries a frozen copy of the terms it started on, and nothing but an explicit, confirmed admin action can move it.If you want a price cut or a bigger allowance to reach existing customers, an administrator applies it deliberately from the Plans page, which shows how many subscribers are on older terms before anything changes.

Credit top-ups are now managed like plans

The three credit top-up bundles — 2,500 for 20,10,000for20, 10,000 for 65, 50,000 for $250 — are catalog entries now rather than values fixed in code. Their prices come from the same record the checkout uses, so what you are shown and what you are charged cannot drift apart.Top-ups stay deliberately dearer per credit than any subscription plan. If you regularly need more credits than your tier includes, upgrading is the cheaper route — a Growth customer needing another 95,000 credits pays about 26% less by moving to Scale than by buying top-ups. Add-on credits still never expire, and are spent only after your monthly allowance is gone.

New plan prices, and a hard ceiling on what one conversation can cost

Plans have been repriced, and the billing engine now caps how much a single conversation can consume.The new plans:**A conversation now costs about 0.24onStarter,0.24 on Starter, 0.21 on Growth and 0.19onScale∗∗—anditcannevercostmorethanabout0.19 on Scale** — and it can never cost more than about 0.75, whatever happens inside it. That ceiling is the real change: previously the gap between a typical conversation and the most expensive one was roughly 2,000x, so a heavy month was impossible to forecast. It is now 3x.Knowledge-base ingestion got substantially cheaper — it is priced close to cost, because it is one-off onboarding work rather than the recurring value you subscribe for. Total ingestion spend roughly halves, and the largest single source measured fell from 39,113 credits to 6,000.
Ingestion is still the biggest non-chat consumer of credits, and it is charged when you add a source and again when you re-crawl it. See Plans and Packaging for what each tier is for, what a credit buys, and what to budget for beyond conversations.
If you are already on a paid plan, your price has not changed. Subscriptions stay on the price they were bought at until you change plans yourself.The conversation estimates on the upgrade page are now accurate. They were calculated from a figure that had no relationship to what a conversation actually costs and overstated capacity by roughly 3.5x. Starter now reads ~116 conversations a month, Growth ~507 — measured across 616 real conversations, not estimated.

See who you’ve actually talked to — Contacts

Talking to someone over WhatsApp used to leave no trace of who they were. Your chat history and operator dashboard showed a fragment of an internal id, and there was no list of the people any agent had spoken to.
  • A new Contacts page shows everyone your agents have talked to, organization-wide — name, phone, which channel and how many agents, and a status (New, Engaged, Qualified, Closed) you can use as a lightweight lead list.
  • Every agent gets its own Contacts tab, filtered to just the people that agent has spoken to.
  • Conversation lists now show who you’re talking to. Chat History, the operator dashboard, and your agent’s own chat page show the person’s name or phone instead of a uuid fragment. A conversation with no identified contact yet still shows something readable rather than a raw id.
  • Your agent can now save what it learns. Turn on Update Contact on an agent’s Tools tab and choose which details it may record — email, company, budget, anything you configure. The agent only saves something the person actually said, never a guess, and it can only ever write to the fields you’ve allowed.
  • One person, one record — even across agents. If someone messages two of your agents, or reaches you on more than one channel, their conversations still show up together under the same contact once a shared identifier (a phone number, an email) ties them together.
  • Existing WhatsApp conversations are already linked — nothing to do on your end.
This applies to WhatsApp today. A web chat visitor becomes a contact once they share an email or phone (or an operator names them) — an anonymous browser visit alone doesn’t create one, since there’d be no real identity behind the row.

Agents that use tools no longer give up mid-conversation

An agent with custom tools would sometimes answer “I’m sorry, I wasn’t able to generate a response” — most often part-way through a back-and-forth, right after you refined what you asked for (“show me something bolder”).
  • The agent can now take several turns with its tools before answering. It could previously use its tools once per message; if it needed to look something up a second time — searching again with different criteria, say — it ran out of room and returned the apology instead of an answer.
  • Nothing about how you configure tools has changed. No setting to update, and existing agents pick this up automatically.
  • Handover to a human is unchanged. If the agent escalates to a person, that still ends its turn immediately, exactly as before.

You can now open the settings for WhatsApp Reply Options

The tool has always had two settings — When to offer options and List button label — and the guide has always described them. There was no way to open them: the Configure link never appeared.
  • Click Configure next to WhatsApp Reply Options on your agent’s Tools tab to reach both.
  • Anything you had already saved is intact. Only where the form appears changed.

Your WhatsApp agent now offers tappable options on its own

Reply options worked, but your agent rarely reached for them. Ask it directly for buttons and you got them; the rest of the time it wrote the choices out as a list you could read but not tap.
  • The agent now offers options whenever its reply presents a real choice — picking a category, a branch, a time slot, or confirming yes or no. That is the normal way to ask a question on WhatsApp now, not something you have to prompt for.
  • It no longer writes choices out as a bulleted list instead. On WhatsApp a list you cannot tap is a worse answer than one you can, and the agent is now told so.
  • Nothing to turn on. If WhatsApp Reply Options is already enabled on your agent’s Tools tab, this applies the next time it replies.
If you have written your own guidance in When to offer options, that still wins — but remember it replaces the default rather than adding to it, so restate WhatsApp’s limits if you rely on them.

Tappable options now show up in your conversation history

When your WhatsApp agent offered reply buttons or a list, the customer saw them — but you didn’t. The transcript showed the agent’s message (“please select the most convenient visit option below”) and then the customer’s answer, with nothing in between to explain what they were choosing from.
  • The options now appear under the agent’s message, laid out the way the customer saw them on WhatsApp: the question, the list’s open button, each option with its second line of detail.
  • You’ll see them everywhere a conversation is shown — your agent’s chat page, Chat History, and the operator dashboard, which matters most when a colleague takes over mid-conversation.
  • They’re a record, not buttons you can press. The customer already answered on WhatsApp; nothing here is clickable.
  • If the options never got through, we say so. WhatsApp only allows them within 24 hours of the customer’s last message, so a set sent after that window closes is shown greyed out and marked “Not delivered”, with the reason — no more wondering why a customer ignored a choice they were never shown. In the rarer case where we can’t tell either way, it says “Delivery unconfirmed” rather than guessing.
Conversations from before this change still show the agent’s text; only options sent from now on are recorded.

Let customers answer with a tap — reply buttons and lists on WhatsApp

Typing on a phone is work. When your agent asks a closed question — shall I book that?, which branch?, what time suits you? — it can now offer the answers as tappable options on WhatsApp Business, and the customer just picks one.
  • Turn it on once, on your agent’s Tools tab. Enable WhatsApp Reply Options. There’s nothing to script per conversation: your agent decides when options genuinely help and asks normally when they don’t.
  • Up to 3 options become buttons; 4 to 10 become a scrollable list with room for a second line of detail on each row. Your agent picks the right one for you.
  • Steer it in your own words. Tell the agent when to offer options (“whenever you ask which branch or which time slot”) and rename the button that opens a longer list (“See available times”).
  • A tap arrives as an ordinary message. The conversation carries on exactly as if the customer had typed the answer, so nothing else about your agent changes.
  • Options need a live conversation. WhatsApp only allows them within 24 hours of the customer’s last message; after that your agent replies through an approved message template, and the customer can still type. Nothing extra is charged for the options themselves.

Reach customers who’ve gone quiet — message templates for WhatsApp Business

WhatsApp closes a conversation 24 hours after the customer’s last message. Until now, anything your operators sent after that simply never arrived: WhatsApp rejected it and the customer heard nothing. Message templates fix that.
  • Write templates on your agent’s Distribute tab. Open WhatsApp Business and you’ll find a Message templates section. Tell us what the message should say, mark the bits that change per message with {{1}}, {{2}} and so on, and give us an example of each — WhatsApp’s reviewers read the message with real values in it. We ask what the message is for in plain language rather than making you guess at WhatsApp’s own category names, which is the most common reason a template gets rejected.
  • WhatsApp reviews every template, usually within a few minutes. You’ll see it move from In review to Approved, or to Rejected with WhatsApp’s reason — the list updates on its own as WhatsApp tells us.
  • Pick a follow-up template and your operators’ replies keep working after 24 hours. Under When a customer has gone quiet, choose an approved template with exactly one blank in it. That blank is where your operator’s actual message goes, so the customer gets what the human wrote — not a generic “we tried to reach you” notice.
  • Two things to know about that. WhatsApp doesn’t allow line breaks inside the blank, so an operator’s reply is flattened onto one paragraph, and a very long reply is shortened — the customer can reply to reopen the conversation and get the rest. WhatsApp also charges for each of these messages, unlike a reply sent inside the 24-hour window.
  • Nothing changes inside the window. While a conversation is live, your operators’ replies go out exactly as they always have.

Reply from the WhatsApp Business app and your operators still see it

If someone on your team answers a customer from the WhatsApp Business app on their phone, that conversation now shows up in Brainstormer instead of happening invisibly. The agent steps aside while the human is talking, and hands the conversation back to the AI when your operator closes it — the same hand-back your operators already use.
  • Turn it on per number. On your agent’s Distribute tab, open WhatsApp Business and tick Capture messages sent from the WhatsApp Business app. It’s off until you switch it on.
  • Your number has to be linked to the app at Meta. This uses Meta’s Coexistence feature, which is set up when the number is connected — if the number isn’t linked to the WhatsApp Business app, there’s nothing for Meta to send us and the setting has no effect.
  • The agent’s own replies are never mistaken for yours, so switching this on doesn’t stop your agent answering.
  • Photos and files your team sends from the app are saved with the conversation, the same way a customer’s are.
  • A message your team sends from the app carries no message fee — no AI reply was generated and nothing was sent on your behalf.

WhatsApp Business messages appear in your credit ledger

Messages on a WhatsApp Business number can now carry a small per-message credit fee, the same way the existing WhatsApp channel does. Where a fee applies, each charge shows up in your usage ledger with a plain description — “WhatsApp Business message received” or “WhatsApp Business reply sent”, with the agent’s name — so WhatsApp Business traffic is separable from your other WhatsApp usage at a glance.
  • Nothing is charged unless the rate is set. The fee is off by default; when it is unset, WhatsApp Business messages cost only the AI response itself, exactly as before.
  • You are never charged for a message you couldn’t get an answer to. If your credits run out, the “temporarily unavailable” reply carries no message fee at all. A message handed to a human operator, or held for approval, is charged as an inbound message only — the notice you get back is not billed as a reply.
  • Only a delivered reply is charged as a reply. If sending fails, the reply fee is not taken.

A second way to connect WhatsApp Business — no Facebook window required

Connecting a WhatsApp Business number no longer requires the Facebook signup window. Open Enter details manually next to Connect with Facebook on the same setup screen, paste in the Phone Number ID and WhatsApp Business Account ID from Meta Business Manager, and connect — the same option is available to you on your agent’s Distribute tab and to staff on the admin onboarding tool.
  • Works today, independent of Facebook sign-in. This uses the same connection logic and the same plan entitlement as “Connect with Facebook,” just without the popup — useful while Facebook sign-in is still being finalized, and a faster path for anyone who already has both IDs in hand.
  • Same clear error states. A number already connected elsewhere, a plan without the channel, or an ID Meta doesn’t recognize each get their own message, matching what “Connect with Facebook” already shows.

Connect your own WhatsApp Business number, without anyone typing an ID

WhatsApp Business is now a channel you set up yourself. Open your agent’s Distribute tab, pick WhatsApp Business, and click Connect WhatsApp Business — a Facebook window opens where you sign in, choose your WhatsApp Business Account and add the phone number the agent should answer on. Nothing is copied out of Meta Business Manager by hand.
  • You keep your own account and number. The connection is made under your own Business Manager, not a shared one, so the number stays yours.
  • The connected state tells you what you connected — display number, the verified business name Meta has on file, and when it was connected. Disconnecting is one click and asks first; you can reconnect any time.
  • When something blocks the connection, it says which thing. A number already connected to another agent, a plan that doesn’t include the channel, and a Meta notification failure each get their own message and their own next step, instead of one generic error.
  • If WhatsApp Business isn’t on your plan, the card says so and links to upgrade rather than letting you walk into a setup that would be refused.
For teams being onboarded by us: staff can now run the same connection with you on a call from an admin tool, so it no longer needs a support ticket and a command line. Sharing a no-login setup link is coming in a later release.WhatsApp still can only reply to people who message your number first — an agent can never start a new conversation.

One place to fix graph problems, and a date range that means what it says

The knowledge graph’s two cleanup pages are now one Issues tab. “Cleanup” and “Optimizer” looked at the same graph and reported different numbers — and the summary on the Graph Overview counted a third thing, with the duplicate count stuck at zero even when hundreds of duplicates were waiting. There is now a single Issues queue, and the counts on the Overview always match it, because both are computed the same way at the same moment.
  • Six clear categories — Duplicates, Removals, Renames, Orphans, Needs review, and Low confidence. Categories with nothing in them are hidden, so you only see what needs attention, and each count on the Overview links straight to its own filtered list.
  • Nothing gets stranded. The old Optimizer page was the only home for “remove” and “rename” suggestions; they are now first-class categories in the queue. Suggestions you have already approved but not yet applied no longer disappear — they show an Apply button instead of a second, meaningless Approve.
  • Built for real volume. Knowledge bases can have thousands of orphaned entities, so the queue paginates and lets you select a whole page and hide or delete it in one confirmed action, instead of clicking through them one at a time.
  • Old Cleanup and Optimizer links keep working — they take you to Issues.
Knowledge base analytics got one shared date range. Picking “Last 7 days” now changes the whole dashboard. Previously four sections quietly ignored the time period and kept showing all-time numbers under a 7-day label, and the chart at the top had its own separate 7/30/90 switcher that could disagree with everything below it.
  • Eleven panels are grouped into Usage, Content and Outcomes tabs instead of one long scroll, with Export to CSV or JSON. The exported file records the exact dates it covers.
  • Learning Progress is always all-time and now says so on the card, rather than appearing to respond to a date range it can’t apply.
  • A few numbers will look different, and are now right: documents that were never retrieved were reporting their chunk count as a retrieval count, so genuinely unused content was never flagged as unused. The stat cards also used to display fixed “+12%” style trend figures that were not based on any data; those are gone.
  • Changing the period while a slower request is still loading can no longer land the old numbers under the new label.
Screenshots in the Knowledge Graph and Analytics guides still show the previous layout; they will be refreshed once this ships to the dev environment.

Knowledge base pages reorganized into one clear set of tabs

Every knowledge base now has one consistent page with six tabs — Overview, Sources, Documents, Search, Graph, and Analytics — instead of information being split unpredictably across a few pages. The knowledge base’s name now shows once at the top and stays there while you move between tabs, and the “Documents” link in the page trail at the top always leads to a real page (it used to be a dead end).
  • Overview is now a real summary: document/chunk/entity/relationship counts, graph build progress, a “Needs attention” panel that flags failed documents or broken sources (click through to fix them), which agents are using this knowledge base, and a settings area where you can finally rename a knowledge base or edit its description from the app — that was only possible by asking support before.
  • Documents now updates itself: after you upload a file, its status moves from “pending” to “processing” to “completed” automatically, without needing to refresh the page. You can filter by status and search by title.
  • Sources got its own dedicated page with clearer sync-status badges, and fixed a bug where an occasional failed background check could get “stuck” showing an error message even after things recovered.

Approval queue renders correctly and Edit & Approve persists edits

The operator approval queue at /operator/approvals displayed empty cards and silently dropped operator edits.
  • Approval cards now show content — the queue renders the bot name (resolved via LEFT JOIN on bots), the end-user’s original message, and the AI’s proposed response. Previously the cards read wrong field names and showed empty panels with a fallback “Agent” label.
  • Edit & Approve now persists edits — the frontend calls POST /hitl/approvals/:id/edit when the operator modifies the response. The edited text is published to the end-user chat, and the record is saved with status edited and the original response preserved. Previously the “Approve” endpoint was called instead, which ignored the body and published the original unedited response.
  • WebSocket broadcasts enriched — the approval.created event now includes botName, userMessage, originalResponse, status, and createdAt, so live-prepended cards render correctly without a separate API fetch.

Operator “Take Over” HTTP 500 on escalation

The operator takeover flow (POST /hitl/escalations) returned HTTP 500 because the operator_takeover event type was missing from the escalation_events CHECK constraint. The escalation row was created before the constraint violation, leaving orphaned active escalations with no event trail.
  • Migration added operator_takeover to the escalation_events event_type CHECK constraint
  • Data hygiene: orphaned active escalations (status=active, zero events) are expired automatically

Consistent feedback across the app

Success, error, and confirmation messages now use one shared set of components everywhere. Confirmation prompts before actions like deleting an agent or a knowledge source are styled dialogs instead of plain browser pop-ups, and status messages (like a save succeeding or a sync failing) now appear as small notifications that fade in and out consistently across the platform.Error and warning banners — the ones that stay on screen, like a failed document upload or a plan limit notice — were previously written by hand in dozens of slightly different styles. They now all share one look, so the same kind of message reads the same way wherever you meet it. Long error messages no longer push pages sideways on a phone, and low-credit warnings no longer interrupt screen readers on every page you visit.

Unified sub-navigation component (TabNav), page headers, and breadcrumbs

In-page tab bars existed as 5+ incompatible hand-rolled variants — border-b-2 underline rows, rows of <Button> used as view switchers, a hardcoded-color segmented control, and a mobile dropdown copy-pasted into 4 files. All 11 call sites (admin, operator, settings, knowledge graph, agent creator, developer, analytics, prompt config) now share one primitive, ui/TabNav.
  • Route mode — items with href render <nav> + <Link>, resolve the active tab from usePathname(), set aria-current="page".
  • State mode — items without href render role="tablist" / role="tab" with arrow-key roving focus, driven by activeId / onChange.
  • Mobile — scrolls horizontally by default, or collapses to a built-in dropdown via mobileMode="dropdown" (recommended at 5+ items or long labels) — replacing the copy-pasted mobile dropdown blocks.
Page titles had the same drift — 14 different hand-rolled <h1> classNames. ui/PageHeader is now the single primitive (title, description, actions, and a tabs slot for TabNav); section layouts (admin, operator, settings, knowledge graph) own the single PageHeader per route and child pages use <h2>.Breadcrumbs now renders on every dashboard route, including top-level ones (⌂ › Agents), not just nested routes — previously it bailed out below two path segments. /home stays bare since it’s the breadcrumb root.Also fixed: the gateway’s /admin/prompt-* proxy routes forwarded the incoming path verbatim to the auth service, but those handlers are mounted under the service’s /auth prefix — the mismatch 404’d upstream and broke /admin/prompt-config. The proxy now prepends /auth to the forwarded path.

Dashboard UI consistency batch

A coherence pass across the dashboard, plus tighter scoping for knowledge-base sync errors.
  • Agent editor — All eight tabs (Configure → Distribute) now share one layout foundation: a common tab header, white-card content sections, and a single alert treatment. The Knowledge tab’s oversized wizard-style hero is gone.
  • Tables — The knowledge base list now uses the same table pattern as Agents and Chat History: one white card with search/filter controls in a connected header, sortable columns retained, and a proper confirm dialog for deletes.
  • Sidebar — Collapse/expand is now a clean wipe: labels clip and fade on one line instead of re-wrapping mid-animation, and icons stay put. Respects reduced-motion preferences.
  • Organization selectors — Superadmins now land on their own organization by default on Agents, Knowledge, and Chat History (with “All Organizations” still selectable). All org dropdowns are alphabetical and searchable, including the sidebar workspace switcher.
  • KB sync errors — Sync failures no longer surface inside the agent editor; they live on the knowledge base list (health column) and detail pages (per-source detail). Error details are hidden from viewer-role users without read access to the affected knowledge base.

Agent Analytics user count metric

The Analytics → Overview dashboard now shows a Users card with active members, total members, and remaining seats against the organization’s plan limit.
  • Backend — platform_billing_plans gained max_users (migration 20260729122306_billing_plan_max_users.sql). New GET /auth/organizations/:id/seat-usage returns { totalMembers, activeMembers, maxUsers, remaining } and is gateway-proxied before the /auth/* wildcard.
  • Frontend — AnalyticsOverview fetches seat usage alongside overview metrics and renders the 6th card. Admin Plans page can edit max_users; the /credits/upgrade plan cards now list user seat limits.
  • Enforcement — AuthService.inviteMember() blocks invites when totalMembers >= maxUsers, returning a plan-limit error.
  • Active users — defined as org members whose last_login_at is within the last 30 days.

Analytics client now routes through the gateway

Replaced direct /api/analytics/* fetches in the analytics components with fetchAnalytics() using NEXT_PUBLIC_API_URL, fixing local 401 Unauthorized errors caused by the Next.js proxy defaulting to the bot service without the internal secret.

Re-processing a knowledge base document from a feed source now works

Clicking Re-process on a document that came from an RSS, blog, crawl, or sitemap source previously left it stuck in “pending” forever — the article URL was handed to the feed parser, which found no feed and quietly did nothing, after the document’s search index entries had already been cleared.
  • Document re-processing now fetches the article as a single page (platform items like YouTube videos keep their platform pipeline).
  • A document re-process no longer counts as a source sync: it doesn’t move the source’s last-sync time, adaptive schedule, sync history, or failure counter.
  • A failed re-process marks only that document as failed instead of every pending document in the source.

WhatsApp Channel Integration

Agents can now receive and respond to WhatsApp messages in real time via WAHA Plus.
  • QR Pairing — Creators pair a dedicated WhatsApp number per agent by scanning a QR code in the Channels tab.
  • Inbound Processing — Messages trigger the full chat pipeline (RAG, guardrails, HITL, billing).
  • Format Adaptation — Markdown is converted to WhatsApp format; citations and product cards are reformatted.
  • File & Voice Support — Optional file uploads and voice transcription via the builtin:voice_input tool.
  • Per-Message Fees — Configurable credit fees for incoming and outgoing messages (admin System Config).
  • HITL Integration — Operators can take over conversations and reply directly via WhatsApp.
  • Documentation — Platform guide and architecture reference added.
  • Frontend — New WhatsAppChannelPage, WhatsAppPairing component, and VoiceRecorderButton for web voice input.

ChromaDB upgraded from 0.6.3 to 1.5.9

The ChromaDB server has been upgraded from chromadb/chroma:0.6.3 (Python/SQLite) to chromadb/chroma:1.5.9 (Rust server) to fix the SQLite dangling-transaction deadlock that caused all POST/write requests to hang after abrupt connection drops.
  • Docker image pinned to chromadb/chroma:1.5.9 in docker-compose.yml
  • Volume mount changed from /chroma/chroma to /data (1.x default persist path)
  • Healthcheck added (bash TCP check on port 8000) for depends_on: condition: service_healthy
  • _initPromise bypass removed from vector-store.service.ts — the 1.x Rust server handles concurrent access natively
  • withChromaLock single-flight queue removed — no longer needed with the concurrent-safe 1.x server
  • All existing KB collections migrated in place with zero data loss

Jest tests now resolve @brainstormer/shared/ssrf correctly

services/knowledge/src/services/__tests__/brand-extraction.service.test.ts failed at suite load — the jest moduleNameMapper catch-all expected

Configurable knowledge-graph and document-summary models

Admins can now change the models used for knowledge-graph extraction and document summarization directly from Admin → System Config → Knowledge Base, without rebuilding or redeploying the knowledge service.
  • New managed platform keys: GRAPH_EXTRACTION_MODEL and SUMMARY_MODEL.
  • Live reads: both keys are resolved at extraction time via platformConfig.get() and invalidated through the existing Redis bus.
  • Save-time validation: model names are checked against the OpenRouter /models list before they are persisted, preventing typos or sunset models from silently breaking ingestion.
  • Failure visibility: graph extraction now records per-call failures and maps them to failed, partial, or completed on kb_documents.graph_status. Repeated failures are logged as errors and flow through the existing GlitchTip → Slack pipeline.

Signup plan cards now match the plan catalog

The Choose your plan signup page now derives numeric plan bullets (monthly credits, agents, and knowledge bases) directly from the live plan configuration in the database. Plan descriptions are now editable by superadmins under Admin → Plans, so the signup page stays in sync with the catalog.
  • Non-enterprise plans show bullets computed from monthlyCredits, maxAgents, and maxKbs.
  • Enterprise bullets continue to come from the plan features field.

Ghost blog platform support for knowledge bases

Ghost is now available as a selectable blog platform in the Add a New Source dialog. Users can add Ghost blogs (.ghost.io or custom domains with /ghost/ path) as knowledge base sources — posts are discovered via the Ghost RSS feed and indexed automatically.
  • Frontend — Ghost appears in the source type grid alongside Substack, Medium, and WordPress with teal brand styling. URL auto-detection works for .ghost.io and /ghost/ paths in both the KB source manager and Creator Wizard.
  • Backend — No changes needed; the existing blog-platform connector and GhostAdapter already handle Ghost feed discovery and ingestion.

Group-based access control for agent distribution

Published agents can now restrict public access to organization members and specific org groups.
  • Backend — agent_distribution_settings gained require_org_membership and allowed_group_ids UUID[] (migration 098). NULL/{} means all groups allowed. A unified checkPublicAccess() guard enforces identity, membership, and group checks on GET /public/agents/:slug and related public conversation paths.
  • Repository helpers — isUserInGroups() and isUserOrgMember() query org_group_members and organization_members directly in the bot service.
  • Gateway — the /public/* lane now strips inbound identity headers, then verifies any optional Authorization: Bearer token and forwards verified user-id/organization-id headers to the bot service.
  • Marketplace — agents with group or org-membership restrictions are excluded from GET /marketplace/agents because anonymous browsers cannot satisfy them.
  • Frontend — the Distribute / Web channel page has a new Require organization membership toggle and a group multi-select. MultiSelectDropdown was renamed to MultiSelect and a reusable Toggle component was extracted.

Visitor question preview in the Creator Wizard

Creators can now see the pre-chat questionnaire exactly as visitors will experience it before publishing an agent.
  • A Preview visitor flow button in Step 2 of the Creator Wizard opens the live visitor questionnaire overlay, including brand colors and logo.
  • A warning banner appears when more than three visitor questions are configured, reminding creators that each extra question increases drop-off.
  • The warning is stronger when every question is required.

Creator Wizard now explains when Continue is disabled

On the Your Content step, the Continue button stays disabled until at least one source is added. A helper hint now appears next to the button so users know what to do next:
  • When no source is added: “Add at least one source to continue”
  • When a URL, file, or shop domain is entered but not yet staged: “Add the source above to continue”
The hint disappears once a source is successfully added and the button becomes active.

Friendly provider-error messages in chat

Chat no longer surfaces raw OpenRouter billing or rate-limit errors to end users. Provider-level failures are mapped to user-friendly messages before reaching the UI. When the provider key hits its credit or token limit, the response uses code: "provider_limit_reached" and shows:
“This assistant is temporarily unavailable. Please try again later.”
The raw provider error, including any API key URLs, is sanitized before logging. Applies to authenticated chat, public widget chat, and chat-core headless consumers.

Indexing-status polling — eliminated double round-trip and error-banner flicker

The GET /bots/:id/indexing-status endpoint was making two identical requests to the knowledge service on every call. The redundant checkKbReadiness() pre-check was removed, cutting knowledge-service load in half across the three frontend components that poll every 15 seconds.
  • Backend — removed the duplicate fetch; the fallback message now surfaces the knowledge service’s error detail when available, falling back to a generic message on network failures.
  • Frontend — setIndexingError(null) now runs only after a successful poll, so the error banner no longer unmounts and remounts on every 15-second tick during sustained failures.

Mandatory knowledge-base readiness before agents go live

Agents can no longer be published without a linked, indexed knowledge base.
  • Backend gates — POST /bots, PUT /bots/:id (when setting isDraft: false), POST /bots/:id/publish, POST /bots/:id/approve, POST /bots/:botId/distribution/publish, and the async provisioning worker all verify readiness before publishing.
  • Fail-closed — if the knowledge service is unreachable, publishing is blocked.
  • Frontend guards — the classic setup flow requires a KB before continuing, the tabbed builder disables the publish toggle without a linked KB, and the Distribute / Go Live pages disable Publish until the readiness check passes.
  • New proxy endpoint — GET /bots/:id/indexing-status surfaces indexing status through the bot service.

KB ingestion failure banner

Knowledge-base ingestion failures are now surfaced prominently on the agent editor and Go Live screens instead of sitting silently in the database.
  • Failure banner — when a linked KB has failed sources, a red Alert banner appears on the agent edit Knowledge Base tab and the Go Live screen, showing the error reason from lastSyncError.
  • One-click retry — each failed source has a [Retry] button that triggers a re-sync via the existing POST /kb/:id/sources/:sourceId/sync endpoint.
  • Deep link to details — a [Details] link opens the KB detail page for full sync history.
  • Backend — GET /knowledge/agents/:agentId/kbs and GET /knowledge/kb now return syncHealth, failedSourceCount, and failedSources[] with {sourceId, sourceUrl, lastSyncError} per failed source.

Smarter retrieval — hybrid search, reranking, and diverse context

The knowledge-base retrieval pipeline was overhauled end to end.
  • Hybrid retrieval — every search now runs a semantic (vector) channel and a keyword (full-text) channel in parallel and fuses them with Reciprocal Rank Fusion. Exact identifiers — SKUs, error codes, names — reliably surface even when the wording differs from your documents.
  • Cross-encoder reranking — fused candidates are re-scored by a reranker that reads the query and each chunk together, for sharper relevance than similarity alone.
  • Diverse, budgeted context — before an agent answers, near-duplicate chunks are dropped (MMR) and total knowledge-base context is capped by a token budget, so retrieval never crowds out the answer.
  • Verified end to end by a new live Playwright suite that uploads a document, waits for indexing, searches, and asserts a grounded, cited answer.

Knowledge-base analytics & the learning loop

A new Analytics dashboard on every knowledge base shows what your content is actually doing — and retrieval now improves on its own as customers use it.
  • Outcome attribution — per-document resource performance (impressions, thumbs, helpfulness tier), a feedback-driven knowledge-gap list (“questions your customers asked that you couldn’t answer well”), and an impression → click → conversion funnel.
  • Learning Progress — a weighted score of the customer signals you’ve collected, the three learning stages it unlocks (smart ranking → learned weights → custom reranker), and how much more signal is needed.
  • Self-improving ranking — resources your customers engage with are automatically boosted in retrieval, floor-gated so early clicks never skew results. Toggle it per knowledge base from the analytics dashboard.

Refer & Earn — referral loop

Share your referral link, and both you and your invitees earn credits when they publish their first agent.
  • Earn your code on first publish — the moment you publish your first agent, a unique referral link is emailed to you and appears on the new Refer & Earn page in the sidebar.
  • Easy sharing — new users can follow your ?ref=CODE link (the code is auto-applied at signup) or enter the code manually in the “Referral code” field on the sign-up form.
  • Both sides earn on activation — when an invitee publishes their first agent, both you and the invitee receive add-on credits (amounts set by platform admins, defaults: 100 for referrers, 50 for referees). The invitee also unlocks their own referral code, keeping the loop going.
  • Per-code cap — each code has a maximum number of successful referrals (default 10) after which it is marked exhausted and no further rewards are issued.
  • Platform admin controls — superadmins can adjust credit amounts, the per-code cap, and toggle the program on/off from Admin → System Config without a redeploy.
  • All reward credits land in the non-expiring add-on credit pool and are emailed when earned.

Faster path to publishing a claimed agent

Publishing an agent after signup is more obvious and less error-prone, and the distribution section is easier to navigate.
  • Land on the publish page after claim signup — users who sign up by claiming an agent now arrive directly on that agent’s Web / Public Page settings (where the URL and Publish button live) instead of the dashboard, so they can publish without hunting for it.
  • URL first — the Web / Public Page now shows the URL slug and public URL at the top, above the landing-page and chat-widget settings.
  • “Channels” is now “Distribute” — the agent-editor tab was renamed, and the per-channel pages show a breadcrumb (Distribute › Web / Public Page) so the active channel is always clear.
  • Conflict-free default slug — the auto-filled URL slug is now checked for uniqueness and suffixed when needed, so a freshly claimed agent no longer fails to publish with a “slug already exists” error on a value the system chose.
  • Plan picker — selecting a plan during signup now scrolls the Continue button into view.
Vision text extraction on indexed images is more reliable and tunable, so editorial overlay text (headlines, venue names, award banners) shows up more consistently in knowledge-base search.
  • Tunable noise floor — the minimum extracted-text length is now a platform setting (Vision OCR Min Text Length, default 20) editable from Admin → System Config, no redeploy required.
  • Transient-failure retry — a failed extraction retries once after a short backoff before giving up, recovering from provider blips that previously lost the text silently.
  • Re-sync backfill — when a synced source re-runs with unchanged media, existing vision text is preserved (no wasted re-extraction) and any image still missing it is filled in, so overlay text becomes searchable without re-embedding unchanged images.

Landing → app agent claim handoff

Agents provisioned from the marketing landing page now transfer into a user’s account when they sign up. A first-party Funnel organization owns the agent and its knowledge base while the visitor previews it, absorbing all pre-signup cost. On signup email verification, the agent and KB re-parent into the new user’s organization — counting against their plan, with no re-indexing and no duplicated LLM cost. The handoff is keyed on the verified email and scoped strictly to the funnel application, so no other tenant’s agent is ever eligible for transfer. First-party funnel only; not a tenant-facing capability.

Searchable knowledge-base linking in the agent editor

The agent Knowledge tab scales to large workspaces and makes attached knowledge bases clear at a glance.
  • Linked knowledge bases appear in their own section at the top, always visible regardless of the search term, each with per-KB retrieval settings and a link to its detail page.
  • A search box finds knowledge bases by name or description; the picker shows a capped set of matches with a “Showing X of Y” hint instead of the whole list.
  • The picker scopes to the agent’s organization, so the agent’s own linked knowledge bases always load.

Read-only mode for the embeddable widget

The embeddable chat can now be locked to a read-only view — messages stay visible but the composer is hidden — so host pages can overlay their own login/payment wall (e.g. after a free-message limit) or show a shared, read-only conversation.
  • Activate on load with ?readonly=1 (or ?mode=readonly) on the iframe URL, or data-readonly="true" on the embed script.
  • Toggle at runtime from host gating logic via BrainstormerWidget.setReadOnly(true|false) — the one inbound command in an otherwise one-way bridge.
  • A new widget:readonly event (with the current flag + counts) fires whenever the mode flips, so the host can sync its overlay.
See Embeddable Chat Engine → Read-only mode.
  • Message copy control: the copy button now sits below each assistant message and is always visible (ChatGPT/Claude style) instead of appearing in a hover-only toolbar — so it works on touch devices. The non-functional “share” control was removed.
  • Direct sign-up landing: marketing traffic can now land straight on the sign-up form by appending ?mode=signup (also ?mode=register or ?signup=1) to the app URL, instead of always opening on the sign-in form.

Widget event counts continue across resumed conversations

When a returning visitor resumed an existing conversation in the embeddable widget, the message:sent / message:received event counts restarted at zero, ignoring the messages the conversation was loaded with. The counts now seed from the loaded message history, so login/payment-wall gating thresholds carry across page reloads instead of resetting.A new conversation:resumed event fires once an existing conversation finishes loading, carrying userMessageCount / assistantMessageCount / messageCount — so the host can re-apply a wall on reload without waiting for the visitor’s next message (widget:ready fires before the conversation loads and cannot carry counts). See Embeddable Chat Engine → Host page events.

Embed widget emits events to the host page

The embeddable chat now posts one-way events to the page that frames it, so host sites can build their own gating — login walls, paywalls, usage analytics — without any two-way coupling.
  • Events: widget:ready, conversation:started, message:sent, message:received, widget:error, delivered via postMessage in a namespaced envelope (source: "brainstormer-widget"). Payloads carry metadata and running per-session message counts — never message text.
  • Loader API: embed.js exposes BrainstormerWidget.on(type, cb) (and "*" for all events), with origin verification handled for you. Raw <iframe> embedders can listen for message directly.
  • Counts are a client-side UX signal — enforce real limits server-side too. See Embeddable Chat Engine → Host page events.

Choose API-key scopes in the Developer Portal

The Generate Key form lets you pick which scopes a brs_live_ key carries, so keys can reach the Agent Provisioning API.
  • Scope picker: chat, kb:read, and agents:write are selectable when generating a key (/developer). New keys default to chat + kb:read; tick agents:write to allow POST /v1/agents:from-url.
  • The key table now shows each key’s granted scopes.
  • A key missing a required scope is rejected by the gateway with 403 insufficient_scope.

Drop-in embed widget + anonymous operator presence

The embeddable chat widget is now live, and public visitors get real-time operator presence.
  • Embed Widget: a dependency-free /embed.js loader injects a floating chat launcher → iframe of a chrome-minimal /embed/:slug page. Configure + copy the snippet in the agent’s Channels → Embed Widget tab (data-slug, data-color, data-position). The agent must be published and not require login.
  • Anonymous operator-presence SSE: GET /api/public/agents/:slug/conversations/:id/events?anonymousId= streams operator messages / takeover / resolution to public visitors (no JWT; ownership scoped by anonymousId). Wired into chat-core’s PublicTransport.subscribeEvents. This also removes the spurious auth errors the public chat history panel used to log.

Anonymous file uploads for embedded chat

Visitors on a published agent page (or the embeddable widget) can now attach files to their messages without logging in — when the agent has file uploads enabled.
  • POST /api/public/agents/:slug/attachments: anonymous, slug + anonymousId scoped multipart upload. Returns an attachment ref ({ id, accessToken }) to pass in the chat message’s new attachments array.
  • Hardened: per-IP / per-anonymousId rate limits, size + MIME allowlist, and magic-byte sniffing (a file whose bytes don’t match its declared type is rejected). See the Anonymous Chat reference.
  • Billing narrations on the provisioning path are now cross-linked (source → agent → KB) instead of blank on the ledger.

Agent Provisioning & Chat API

A public, API-key-authenticated capability that lets any client app build a chat agent from a creator’s YouTube or Instagram URL — observe the build asynchronously, then chat anonymously with streaming responses grounded in the creator’s content. No logged-in Brainstormer user required.
  • POST /v1/agents:from-url: kick off an async build from a channel URL, returning 202 with a buildId — non-blocking. Supports mode (bounded preview vs. full), intent, model, Idempotency-Key, and deliver.{stream,webhookUrl}.
  • Live progress (SSE): GET /v1/agents/builds/:id/events streams one ProvisioningEvent per phase transition (queued → detecting → scraping → analyzing → provisioning → indexing → ready/failed) with phase-weighted, display-ready progress copy. Replays state on connect; closes on terminal.
  • Polling snapshot: GET /v1/agents/builds/:id returns the latest ProvisioningEvent (same shape as SSE) for stateless / email-me-a-link backends.
  • HMAC-signed webhook: optional out-of-band delivery of the terminal event, signed X-Brainstormer-Signature: sha256=<hmac>, with retry/backoff.
  • Anonymous chat: once ready, browsers chat directly via the slug-based /api/public/agents/:slug/* endpoints — no API key, with optional SSE token streaming and starterQuestions to seed the UI.
  • Auth & abuse controls: agents:write scope (403 insufficient_scope), no-secrets-in-browser Pattern A backend proxy, Cloudflare Turnstile, per-key + per-IP rate limits (429 + Retry-After), idempotency, and handle dedup.
  • Structured error model: a flat ProvisioningErrorCode enum, each carrying retryable semantics, plus partial-success warning for thin content.
  • Developer docs: new API reference (from-url, build snapshot, SSE, webhook, anonymous chat), a 5-minute quickstart with a Next.js Pattern A proxy, auth & rate-limits and concepts guides, plus a machine-readable llms.txt.

Real-Time SSE Streaming for Chat

Chat responses now stream token-by-token in real-time instead of waiting for the full response. First token appears in under 1 second (previously 40-86 seconds of blank waiting).
  • Real SSE streaming: Tokens arrive via Server-Sent Events through all 4 layers (LangChain → Bot Service → Gateway → Frontend)
  • Non-streaming model fallback: Models that don’t support streaming automatically fall back to invoke-then-send
  • Parallelized setup: Independent pre-LLM calls (prompt resolution, conversation history, bot config) run concurrently via Promise.all
  • Latency instrumentation: Every chat request logs a structured timing breakdown (KB retrieval, TTFT, tokens/sec, post-processing) for ongoing optimization
  • Citation instructions: KB context now instructs the LLM to include [1], [2] citation markers in responses
  • Auto-linked @mentions: Instagram @handles in chat responses are now clickable links. URLs auto-linked via GitHub Flavored Markdown.
  • Chat button on editor: Published agents now have a “Chat” button in the editor header for quick access

Enhanced Creator Voice Analysis

The creator wizard now analyzes actual social media content (Instagram posts, videos, images) to generate voice-accurate system prompts instead of scraping empty homepage HTML.
  • Platform adapter integration: Instagram, YouTube, TikTok, Twitter URLs use Apify adapters to fetch real posts with captions, engagement metrics, and media
  • Media processing: Up to 5 media items get transcribed (video/audio) or vision-extracted (images) during light-scrape for richer voice analysis
  • Improved LLM prompt: Creator analysis now extracts verbal patterns, catchphrases, few-shot examples, and top-performing topics
  • Wizard UX: Phase-based progress messages (“Fetching posts…”, “Transcribing videos…”), skip link, enrichment summary badge
  • Generate from KB button: Re-generate a voice-accurate prompt anytime from the prompt editor using existing KB content
  • Graceful degradation: Every processing step has fallbacks — Apify fails → URLFetcher, transcription fails → caption only, vision fails → skip

Human-in-the-Loop (HITL) System

Complete operator oversight system for AI agent conversations — escalation, approval workflows, queue management, and real-time operator dashboard.
  • Escalation workflow: AI-triggered or manual operator takeover with configurable escalation mode (both, AI-only, manual-only)
  • Approval workflow: Hold AI responses for operator review before delivery (off, all responses, or AI-selected)
  • Queue management: Auto-assign queued escalations when operators connect, configurable timeout (60s–24h), outside-hours behavior (queue, message-only, fallback email)
  • Operator dashboard: Real-time escalation queue, stats bar, quick actions, WebSocket-powered live updates
  • Browser notifications: Notification API alerts for new escalations, assignments, and messages when tab is unfocused
  • In-app notification bell: Sidebar badge with pending count and recent alerts dropdown, visible from any page
  • Customizable messages: 8 user-facing messages configurable per-agent (escalation started, operator joined, queued, expired, approval pending, etc.)
  • Concurrency safety: Atomic claim/approval operations prevent double-claim race conditions in multi-operator environments
  • Reusable email verification: Generic OTP-based email verification system with <VerifiedEmailInput> component, used for fallback email config and dashboard email verification banner

Chat Stabilization — Routing, Citations, Prompt Editor

Several fixes consolidating the chat experience after the widget config rollout.
  • Path-based conversation URLs via [[...conversationId]] catch-all for both dashboard and public chat pages
  • Chat history continues conversations via path, not query param — prevents the variable form from re-prompting on existing conversations
  • Citation persistence: non-streaming path embeds sources in message metadata; frontend reads persisted metadata first, falls back to transient lastResponse
  • KB context prompt strengthened with explicit citation format rules and examples
  • CitationTooltip: richer hover tooltips with thumbnails and purple badges
  • EnhancedChatInterface: SSE + HITL updates aligned with new routing and metadata-sourced citations

Incremental Crawl Ingestion + Centralized Scraping

Knowledge-base ingestion now streams results progressively, and an internal meta-task model is configurable.
  • Crawl workers deliver pages incrementally as they’re fetched instead of waiting for the full batch; default page limit lowered to reduce over-crawl on large sites
  • Centralized scraping service consolidates URL fetching behind one adapter used by the crawler, light-scrape, and manual-sync paths
  • Internal “meta-task” model (used for creator analysis, parameter suggestion, summarization) is now configurable via platform config + org-level override — organizations can choose a cheaper/faster model for internal LLM work without affecting chat

Widget Config, Appearance Tab, Editor Reorganization

Agent appearance and end-user experience are now configured from a single Appearance tab on the editor, persisted in a new widget_config JSONB on bots (with org-level defaults in widget_defaults).
  • Editor reorganized from 8 tabs to 6 with header actions for Save / Preview / Publish
  • New Appearance tab — branding, chat styling, variable form sections
  • ChatThemeWrapper injects widget config as CSS variables into the chat surface
  • VariableFormOverlay — pre-chat form component rendered when the agent declares required template variables
  • Widget theming + variable form integrated into both authenticated and public chat interfaces
  • Org-level widget defaults configurable from Organization Settings → Brand Defaults
  • Draft preview banner on chat page when previewing an unpublished agent
  • Welcome message moved out of the tool system and into widget_config; builtin:variable_collection tool (non-functional) removed
  • Template variable selector added to the welcome message prompt editor
  • Public agent endpoint returns the merged org-default + agent widget config
  • New endpoints: GET /bots/:id/widget-config, PUT /bots/:id/widget-config, GET/PUT /auth/organizations/:id/widget-defaults
  • Shared WidgetConfig types + merge utility in packages/shared
  • Distribution simplified: visibility removed in favour of URL-based access; old /distribute page redirects to the editor Distribute tab

Unified Onboarding + Intent-Driven Agent Creation

Dual onboarding wizards (OrgOnboardingWizard, OnboardingWizard) replaced with a single UnifiedOnboardingWizard that handles plan selection and team setup in one flow. Agent creation now asks for an intent up front.
  • Five intents: Creator/Brand, Customer Support, Knowledge Assistant, Sales & Outreach, Personal Knowledge Base
  • Intent drives the generated system prompt, default tool selection, KB source ordering, and creator-analysis prompts
  • Billing plans moved from hardcoded ONBOARDING_PLANS to a DB-driven API (GET /auth/billing-plans) with Stripe-ready columns
  • New DB: bots.intent column, billing_plans table with Stripe pricing columns, intent-specific system prompt defaults
  • KBSourceAdder reorders sources based on the chosen intent
  • Fixed onboarding redirect loop + KB source icon mapping
  • Fixed race where navigating to CreatorWizard would briefly bounce through the onboarding redirect guard

Variable Form + Prompt Editor Reliability

Cluster of fixes around the variable form flow and prompt editor interactions.
  • Delay conversation creation until the variable form is submitted (previously created an orphan conversation)
  • Load stored conversation variables during chat + wait for widget config before deciding whether to show the variable form
  • Fix stale closure in the variable form → conversation creation flow
  • Prevent “Update Agent” from overwriting prompt editor changes made since load
  • Serialize template variables as {{name}} in the rich-text markdown output so they round-trip through saves
  • Normalize public agent response to include templateVariables on the agent object (matches authenticated shape)

Agent Prompt Configuration System

Unified, versioned prompt management replacing all hardcoded LLM prompts platform-wide.
  • New tables: prompt_type_registry, system_prompt_defaults, system_prompt_default_versions, bot_prompt_configs, bot_prompt_config_versions, conversation_variables; streaming_enabled added to bots
  • Three-tier prompt resolution: bot override, system default, code constant fallback
  • fixed (static) and generated (LLM-driven) modes per prompt type, per agent
  • Welcome message returned in POST /bots/:id/conversations response; supports streaming in generated mode
  • Dynamic variables ({{variable_name}}) with five-source precedence chain (per-message > sensitive > client > agent > system)
  • Sensitive variables stored encrypted via POST endpoint or signed JWT context tokens
  • Semantic versioning (major.minor) with auto-generated changelogs and rollback on all prompt configs
  • streaming_enabled field on bots; effective streaming = bot setting AND per-request stream param
  • Shared prompt rendering engine: packages/shared/src/prompt-renderer.ts
  • Bot service CRUD endpoints: GET/PUT/DELETE /bots/:id/prompt-configs/:type, version history, rollback
  • Auth service superadmin endpoints: prompt type registry CRUD, system defaults management with versioning
  • All endpoints proxied through gateway
  • PromptConfigEditor React component for agent edit page and admin UI
  • Creator wizard extended: AI analysis now returns suggestedWelcomeMessage + suggestedWelcomePrompt
  • Existing bots.system_prompt values migrated to bot_prompt_configs (backward compat preserved)
  • All previously hardcoded prompts seeded as system defaults
  • Billing integrated: generated mode prompts call record_external_cost_event()

Knowledge Graph + Document Registry + Summary Index

PostgreSQL-based knowledge graph for enhanced RAG retrieval.
  • 4 new database tables: kg_document_registry, kg_entities, kg_relationships, kg_communities; new columns on kb_documents for graph metadata
  • Multimodal entity extraction from text, images (vision model), video frames, and audio transcripts
  • Document summary index generates per-document summaries for KB map overview
  • Graph query service with entity search, relationship traversal, and community detection
  • User-controlled visual entity extraction configurable at source and document levels
  • New API endpoints: /map, /search/enhanced, /graph/search, /graph/stats, /reindex-graph, /graph/entities, /graph/visualization
  • Enhanced bot retrieval with KB map + graph context injected into agent chat
  • Frontend Graph Explorer page with force-directed visualization, Document Knowledge Panel, and Graph Stats section
  • Async graph processing via BullMQ graph-indexing queue
  • PostgreSQL-based graph storage with recursive CTE traversal (no Neo4j dependency)

Unified Content Processing Pipeline

Introduced ContentConnector pattern with ConnectorRegistry for all KB source ingestion.
  • All connectors (YouTube, Instagram, Twitter, RSS, blog-platform, URL, document) produce standardized NormalizedContent[] with dedup keys and content hashes
  • Vision text extraction via OpenRouter for images and PDF pages
  • Transcription service for audio and video content
  • ContentProcessingPipeline orchestrates extraction, chunking, embedding, and vector storage in a single flow
  • Extensible: new source types require only a new connector implementing the ContentConnector interface

Gemini Multimodal Embeddings Integration

Replaced OpenAI text-only embeddings with Gemini Embedding 2 (gemini-embedding-exp-03-07) for native multimodal RAG across the Knowledge Base system.
  • Text, image, video, and audio content embedded natively via @google/genai at 3072 dimensions (up from 1536)
  • User-configurable media embedding strategy per KB: “native” (embed media directly) or “transcription” (Whisper to text to embed)
  • Per-post document creation for social media (YouTube, Instagram) instead of concatenated text blobs
  • Media storage service with ffmpeg-based video/audio splitting for content exceeding Gemini limits
  • Per-modality billing integration (text per 1k chars, image flat rate, video/audio per second) via record_external_cost_event
  • Enhanced bot citations with platform badges, thumbnails, published dates, and “View Original” links
  • KB analytics dashboard with 5 new components: QueryTrendsChart, AgentUsageChart, KnowledgeGapsTable, ContentUtilizationTable, CostBreakdownCard
  • PATCH endpoint for KB settings updates (media embedding strategy toggle)
  • Section-based analytics API for lazy-loaded dashboard sections

Gemini Embedding 2 Multimodal RAG POC

Completed proof-of-concept validating native text-to-video, text-to-image, cross-language (Spanish/Hindi to English), and image-to-image retrieval using gemini-embedding-2-preview (8/9 tests passed, 89%). PDF native embedding unreliable (workaround: convert to images); multimodal queries underperform.

Light Scrape Creator Wizard

Replaced the 4-step creator wizard (Sources, Build Knowledge, AI Profile, Launch) with a 3-step flow (Sources, AI Profile, Launch) that eliminates the blocking KB sync wait.
  • New POST /knowledge/light-scrape endpoint extracts URL content instantly without full indexing
  • New POST /knowledge/kb/:id/sources/batch endpoint for bulk source creation after agent is created
  • analyzeScrapedContent() accepts raw scraped content directly instead of requiring a knowledgeBaseId
  • POST /bots/creator-analysis now accepts either { knowledgeBaseId } or { scrapedContent[] }, keeping backward compatibility
  • CreatorWizard rewritten: step 1 collects draft sources, step 2 runs light scrape + AI analysis in parallel, step 3 creates agent + KB + enqueues async sync
  • Net result: wizard completes in seconds instead of 5+ minutes; full KB sync runs asynchronously in the background

AI-Powered Creator Onboarding Wizard

Redesigned creator wizard from 5-step (profile, sources, ingest, prompt, launch) to a 4-step AI-driven flow (sources, ingest, analyze, launch).
  • New creator-analysis.service.ts analyzes ingested KB content via OpenRouter (claude-3-haiku) to extract creator profile and system prompt automatically
  • New POST /bots/creator-analysis endpoint accepts a KB ID and returns creatorProfile + systemPrompt
  • Profile step eliminated: creator identity is inferred from their own content rather than entered manually

Additional Features

  • Added onboarding path architecture for /agents/create to support multiple low-friction onboarding tracks (creator, classic)
  • Enhanced chat message rendering with repositioned actions within bubbles
  • Improved error handling with input validation in LangChain service
  • Complete multi-modal architecture design (WebRTC + SSE + WebSocket)
  • API Gateway service with health checks and service proxy
  • Auth Service with JWT and organization context
  • PostgreSQL database schema with multi-tenant support
  • Comprehensive development tooling and Git workflow

Bug Fixes

  • Fixed message actions positioning for better UX
  • Added null checks and filtering for invalid chat messages
  • Improved input validation with detailed error messages

Documentation Updates

  • Detailed architecture documentation for multi-modal platform
  • Implementation plan with parallel development strategy
  • Contributing guide with sophisticated code management protocol
  • Complete development setup and testing procedures

Build Infrastructure

  • Monorepo setup with Turborepo
  • Comprehensive TypeScript configuration
  • ESLint and Prettier code formatting
  • Husky Git hooks with conventional commits
  • Automated versioning and changelog generation

v0.1.0

Foundation Release

Initial project setup establishing the complete foundation for Brainstormer V2 — a next-generation AI chatbot platform built for multi-modal interactions (text, voice, and video) with enterprise-grade features.
  • Initial project setup with microservices architecture
  • Foundation for multi-modal AI chatbot platform
  • Enterprise-grade multi-tenant organization support
  • Real-time communication protocol design
Key Achievements:
  • Production-ready JWT authentication with organization context
  • Multi-tenant architecture: B2B-ready with custom billing rates per organization
  • API Gateway with service discovery, health checks, and proxy routing
  • Optimized PostgreSQL schema with proper relationships
  • Excellent development tooling with hot-reload and comprehensive logging

Initial Build Setup

  • Project structure with monorepo approach
  • Complete development environment setup
  • Docker Compose for local development
  • PostgreSQL database with proper migrations