feat(ui): rewrite the web interface on Vite, and give conversations a first-class API - #2569
Open
Charlesthebird wants to merge 1 commit into
Open
feat(ui): rewrite the web interface on Vite, and give conversations a first-class API#2569Charlesthebird wants to merge 1 commit into
Charlesthebird wants to merge 1 commit into
Conversation
Charlesthebird
force-pushed
the
charlesthebird/uiRewrite
branch
from
August 25, 2026 23:43
9d67c52 to
6426683
Compare
Charlesthebird
force-pushed
the
charlesthebird/uiRewrite
branch
4 times, most recently
from
August 26, 2026 00:25
06e71ff to
11aaee0
Compare
Collaborator
Author
kagent-ui-crud.mp4🤖 written by Claude |
Collaborator
Author
kagent-ui-agent-chat.mp4🤖 written by Claude |
Charlesthebird
force-pushed
the
charlesthebird/uiRewrite
branch
3 times, most recently
from
August 26, 2026 01:14
3228eee to
8264ec6
Compare
… first-class API The Next.js app is replaced by a Vite + React 19 single-page app. Routing is React Router's, reads go through SWR, components come from antd 6 and styling from Emotion. Settings reach the app at runtime from `window.environmentVariables` rather than being frozen into a build, so one image serves every deployment. The pages follow the v1alpha3 model rather than the one the old app was written for. An agent is not a resource: it is what exists once a Harness admits an AgentTemplate, read out of `AgentTemplate.status.harnesses[]`. The agents landing page says so, in an overview that maps the four concepts — AgentTemplate, Harness, Agent, AgentInstance — onto the Agent Substrate words for the same things, and its three tabs are the way to each. An agent's own page lists its conversations, and a conversation is the chat. Chat runs over A2A on gRPC-Web, which needed a server-side half: - `AgentInstance` gains a name, end to end — migration, sqlc, store, proto, service, gRPC handler and policy — so a conversation can be called something. Additive: an empty name renders by id. - `ListAgentInstances` takes a query rather than six positional arguments, and can narrow to one agent by template and harness. The pair is resolved through `prepared_revision`, so no new column is needed and rows written before the filter existed still match. - The A2A gateway serves an instance in any state for reads, so a suspended conversation can still be opened and its transcript read. - A share resolves to the share *and* the instance's owner, because that is what a share grants: the reader stays themselves, and the token widens what they may read. - The gRPC server can hand its gRPC-Web handler to the HTTP server, so a browser reaches the services over the origin it was served from. The split happens outside the router's middleware chain: that chain is for REST-shaped handlers, and a gRPC-Web frame neither survives it nor needs it. Test coverage is 376 unit tests and 88 browser tests, all against the real pages. What could not be covered honestly is written down in `ui/playwright/DEFERRED.md` with the surface each spec is waiting on, rather than committed as a skipped test — a skipped spec reads as coverage and that list does not. `ui/dev-scripts/` builds a Kind cluster with kagent on it in one command, for anyone who wants to try the app against a real backend. Without a cluster, `ENABLE_MOCK_UI=true` serves every page from in-browser fixtures, and each such page says on itself that the data is not real. Signed-off-by: Nicholas Bucher <behappy54321@gmail.com>
Charlesthebird
force-pushed
the
charlesthebird/uiRewrite
branch
from
August 26, 2026 01:50
8264ec6 to
ec60b82
Compare
Charlesthebird
marked this pull request as ready for review
August 26, 2026 02:21
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Rebuilds the web interface on Vite + React 19 — React Router, SWR, antd 6, Emotion. It is a static bundle behind nginx with no server process; settings come from
window.environmentVariables, rewritten by the container on every start, so one image serves every deployment.The application API is reached over gRPC-Web:
grpcserver.WebHandlerwraps the existing*grpc.Server, and the HTTP server routes gRPC-Web requests to it ahead of its middleware chain.Note
Reading the diff. 616 of the 696 files are
ui/, which is the rewrite's tree — read it as a new app, not as a diff. The other 80 are three things:helm/— the UI pod stops running a Next.js server and becomes nginx serving a static bundle, songinx.conf,supervisord.conf,ui-deployment.yamland the UI values change together with their tests.go/andproto/— the gRPC-Web seam (grpcserver/grpcweb.go,httpserver/server.go,app.go) and the fiveAgentInstancechanges below, plus generated proto and sqlc output.CLAUDE.mdand.nvmrc— the repo guide's UI section, and the pinned Node version.Testing this PR
One command builds a Kind cluster and installs this checkout on it — controller, UI and agent runtime all built from the working tree, over the chart's published images. It ends holding a port-forward, so the last thing it prints is a working URL.
./ui/dev-scripts/setup-cluster.sh # ~25 min, mostly image buildshttp://localhost:8080
Tip
The script also leaves one agent on the cluster — an
assistanttemplate on akagentharness — so Agents has something in it and you can send a message straight away, without creating anything first.Warning
make create-kind-cluster && make helm-installdoes not work, and fails silently five different ways — including that the chart installs published images, so none of your changes are on the cluster while everything looks healthy.ui/dev-scripts/README.mdcovers each one, and the dev-server loop for iterating.UI Extensions
The app declares vendor extension points anyone can use to add to it or restyle it, all in one configuration object:
navItemsordernavOverridesroutesrouteHandlesslotsformFieldstableColumnsapiprovidersthemeshellbrandingproviderIconsagentLinksInstalling one is two edits: build a
VendorExtensionConfig, then pointsrc/vendorExtensions/activeConfig.tsat it. Overriding theme tokens restyles the app's own components, not just the extension's.Note
📖
ui/docs/vendor-extensions.md— every extension point and what it receives. Worth reading before reviewing thevendorExtensions/tree.Substrate
The pages follow the CRDs. An Agent is derived, not a resource — a
Harness×AgentTemplatepair read fromAgentTemplate.status.harnesses[], so there is no "New agent" button. The landing page explains the four concepts over three tabs; an agent's page lists its conversations, and a conversation is anAgentInstance.Five additive server-side changes, none affecting an existing caller:
AgentInstancegains anameListAgentInstancestakes a queryprepared_revision.app.godefaults the A2A gatewayTest Coverage
376 unit tests. The browser suite runs in Chromium and Firefox, plus a Chromium pass with the example extension installed.
Follow Ups
UI Playwright E2Eworkflow that did that is removed here, along with the harness it drove (playwright/scripts/setup.sh,playwright/mocks/server.mjs); restoring it is follow-up work.yarn test:pw:livecovers a few journeys against a real cluster in the meantime.ui/playwright/DEFERRED.mdlists the rest, and the surface each spec waits on. Nothing is committed as a skipped test.Note
go test ./...fails one pre-existing test on macOS —TestFetchSourceReusesExistingMaterialization,/varvs/private/var, in a package this change does not touch.Upgrade Notes
Caution
Breaking. The chart no longer sets
NEXT_PUBLIC_BACKEND_URL,BACKEND_INTERNAL_URLorBACKEND_GRPC_URL, and dropsui.backendInternalUrl,ui.backendGrpcUrlandui.volumes.nextjsCache.The oauth2-proxy
skip-auth-regexnow names/assets/andenv-config.jsinstead of the Next.js paths, which no longer exist.Also included, unrelated to the rewrite:
helm/tools/grafana-mcpnow passes-allowed-hosts. The server rejects any Host header it was not told about, so one reached over the cluster network answered the MCP handshake withForbidden— theRemoteMCPServersatAccepted=Falseand every agent using it failed to build its tool set. Found while testing the tools pages; happy to split it out if preferred.🤖 written by Claude