Skip to content

Latest commit

 

History

History
182 lines (148 loc) · 6.72 KB

File metadata and controls

182 lines (148 loc) · 6.72 KB

kbagent web UI

Two ways to run the UI:

  • End-user / single-process -- one Python command, no Node runtime needed: kbagent serve --ui. FastAPI mounts the built React SPA on /, injects the bearer token into index.html, and rewrites /api/* to bare API routes. Use this for "just give me the UI" deployments.
  • Dev mode (3 terminals) -- Vite dev server + Node BFF + kbagent serve. Used when iterating on the React app: hot reload, source maps, the works. See Dev mode below.

Single-process mode (recommended for users)

Install from git (recommended)

# Node 20+ on PATH so the build hook can compile the SPA into the wheel:
uv tool install --with 'keboola-cli[server]' 'git+https://github.com/keboola/cli'

# Run:
kbagent serve --ui
# Open the URL printed at startup -- the browser is auto-authenticated.

The wheel ships with the React SPA inside it (keboola_agent_cli/_ui_dist/). A hatchling build hook (hatch_build.py) runs npm ci && npm run build during wheel creation so uv tool install git+... produces a self-contained install. If Node is unavailable on the install host the CLI still works but kbagent serve --ui will exit with a "no UI bundled" error and instructions to rebuild.

From a local checkout (editable install)

uv pip install -e ".[server]"
(cd web/frontend && npm install && npm run build)   # produces web/frontend/dist
uv run kbagent serve --ui --port 8001 --config-dir ~/.config/keboola-agent-cli

What --ui does on top of kbagent serve:

  1. Mounts web/frontend/dist at / so the SPA loads from the same port as the API.
  2. Server-renders index.html with <script>window.__KBAGENT_TOKEN = "..."</script> so the SPA boots already authenticated. No paste step, no Node BFF.
  3. Adds a path-rewrite middleware so the SPA's existing /api/* calls reach the bare endpoints (/projects, /configs, ...).
  4. Accepts ?_kbagent_token=... as a fallback because EventSource (the SSE primitive used on the Jobs page) cannot send custom headers.

--ui-dist PATH overrides the dist location; $KBAGENT_UI_DIST works the same way. Both imply --ui.

The bearer token is still printed at startup so curl / scripts / kbagent http get keep working alongside the browser session.

Architecture

  React SPA  (web/frontend, Vite + TanStack Query + Tailwind + Monaco + Mermaid)
      |
      |  Single-process mode: SPA + API on the same FastAPI port,
      |                        token injected into index.html.
      |
      |  Dev mode: SPA via Vite dev server, /api/* proxied to ↓
      v
  Node BFF   (web/backend, Fastify + undici)         (DEV / OPTIONAL)
      |  REST + SSE injects bearer token, no business logic
      v
  kbagent serve  (Python, FastAPI + uvicorn)
      |
      v
  Keboola APIs (Storage, Queue, Manage, AI, MCP)

The BFF is now optional -- it exists to enable the Vite dev workflow (hot reload across all three layers) and to host the SPA from a different process when that's preferred. Production deployments can run a single uvicorn process via --ui.

Building your own client instead of the bundled SPA? Run plain kbagent serve (no --ui). It exposes the same REST + SSE endpoints and an OpenAPI schema at /openapi.json; authenticate with the bearer token printed at startup or via $KBAGENT_SERVE_TOKEN. The kbagent http get|post|patch|delete CLI is a thin wrapper for shell use.

Dev mode (three terminals)

Use this when editing React / TypeScript and you want hot reload.

Prerequisite: uv pip install -e ".[server]", Node 20+, and (cd web/backend && npm install) / (cd web/frontend && npm install).

Terminal 1 -- the kbagent kernel

uv run kbagent serve --port 8001 --config-dir /tmp/kbagent/.kbagent
# Prints a bearer token on startup -- copy it.

Terminal 2 -- the Node BFF

cd web/backend
KBAGENT_SERVE_TOKEN=<token-from-terminal-1> PORT=8000 npm run dev

Terminal 3 -- the React dev server

cd web/frontend
npm run dev
# Open http://localhost:5173/

The Vite dev server proxies /api/* and /__bff/* to the BFF; the BFF attaches the bearer token and forwards to kbagent serve. Hot reload works for all three layers.

Production-only BFF mode (legacy)

If you'd rather keep the BFF in production (e.g. you've got auth / logging middleware in Fastify you want to preserve), the original flow still works:

make web-build        # builds the React app into web/frontend/dist
uv run kbagent serve --port 8001 --config-dir ~/.config/keboola-agent-cli &
cd web/backend
STATIC_DIR=../frontend/dist \
KBAGENT_SERVE_TOKEN=<token> \
PORT=8000 npm start
# Open http://localhost:8000/

Architecture notes

  • No business logic in the BFF: it injects the bearer token and proxies (REST + SSE) verbatim. If you want a different UI language, swap the BFF -- the React app talks to it through /api/*, the BFF talks to kbagent serve through OpenAPI.
  • Manage tokens are per-request: writing operations that need KBC_MANAGE_API_TOKEN (org setup, member invites/removes) prompt for the token in a modal and pass it as X-Manage-Token for that one request. Never persisted, never logged.
  • SSE streams: jobs page subscribes to /api/jobs/{project}/{id}/stream for live status + log events. The BFF passes the chunks through; the React EventSource API receives them directly.
  • SQL workspaces: Monaco editor + /api/workspaces/.../query with CSV-rendering of statement results.
  • MCP tools: each tool's inputSchema is rendered as a generic JSON input on the MCP page so you can call any tool the server exposes without UI changes.
  • Lineage: cross-project bucket-sharing graph rendered as a Mermaid diagram + tabular edge list.

Repo layout

web/
  backend/                 Node 20 + Fastify (TypeScript)
    src/
      server.ts            entrypoint
      proxy.ts             REST + SSE proxy with bearer auth injection
      config.ts            env-driven config
    package.json
    tsconfig.json
  frontend/                React 18 + Vite + Tailwind + TanStack Query
    src/
      api/client.ts        thin fetch wrapper + SSE helper
      state.tsx            global UI state (selected project, branch, page)
      types.ts             permissive mirror of kbagent service shapes
      layout/               Sidebar, TopBar, StatusBar, Shell
      components/           Empty, Table, JsonView, ManageTokenModal
      pages/                one file per feature area (20 pages)
      App.tsx              page router (state-driven)
      main.tsx             React entry
      index.css             Tailwind base + NERD theme components
    index.html
    vite.config.ts
    tailwind.config.ts
    package.json
    tsconfig.json