Skip to content

Commit 4a89e78

Browse files
authored
feat(dashboard): rename vis → dashboard and add agent-tracing dashboard (#137)
* feat(dashboard): add the agent-tracing dashboard (web UI, CLI, API, packaging) Introduce `pythinker dashboard` — a local web UI for inspecting agent sessions: wire events, context messages, state, sub-agents, a dual view, tool statistics, and usage over time. Served by a FastAPI backend (`pythinker_code.dashboard`) under `/api/dashboard`, with the React/Vite frontend bundled at build time (`make build-dashboard`, wired into the wheel, PyInstaller binaries, and the Linux/Windows installers). Reachable from the interactive shell via `/reports` (alias `/dashboard`). Also fixes correctness issues found in review: attach the session auth header to the import and delete calls; log previously-swallowed exceptions in the session/statistics APIs and the build script; group sub-agent events by a stable key; and gate the number-key tab shortcuts to the in-session view. * docs(dashboard): document the agent-tracing dashboard Add the dashboard reference page, wire up navigation and cross-links, refresh the architecture and configuration docs, and add a CHANGELOG entry introducing `pythinker dashboard`. * fix(dashboard): sync lockfile and address review findings - Regenerate dashboard/package-lock.json to restore the nested @emnapi deps so the onefile build's `npm ci` succeeds (was failing on every platform in PR #137 CI). - Open the browser at localhost for `::` binds, not just `0.0.0.0`, so the URL stays within the allowed origins (loopback_browser_host helper + test). - use-theme: fall back to the legacy "vis-theme" key for upgraders. - Help overlay: move the session-gated 1-5 tab shortcuts out of "Global" into a "Session Views" group. - AGENTS.md: drop stale "visualization" wording for the dashboard targets. - Assert the dashboard missing-assets 503 names the expected static path. * fix(dashboard): center the Daily Usage chart instead of full-width The Daily Usage line chart stretched to the full 1400px content width, leaving the sparse 30-day series looking over-extended. Cap the card at max-w-3xl and center it (matching loading skeleton) so it stays centered and readable on wide screens. * fix(dashboard): resolve CodeRabbit findings and fix lockfile @emnapi sync - Add -> None return type to SwitchToDashboard.__init__ (ANN204) - Rename unused args to _args in reports() slash command (ARG001) - Add IPv6 :: host to allowed_origins in dashboard app - Add @emnapi/core@1.11.1 and @emnapi/runtime@1.11.1 to dashboard lockfile The build was failing on all platforms because npm ci could not find @emnapi/core@1.11.1 and @emnapi/runtime@1.11.1 in the lockfile. These are needed by @tailwindcss/oxide-wasm32-wasi which pins ^1.10.0 (now resolved to 1.11.1 on the registry). Added the missing top-level entries.
1 parent bd23c21 commit 4a89e78

96 files changed

Lines changed: 415 additions & 272 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/dependabot.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ updates:
3636
- package-ecosystem: "npm"
3737
directories:
3838
- "/web"
39-
- "/vis"
39+
- "/dashboard"
4040
- "/docs"
4141
- "/packages/install-counter-worker"
4242
- "/examples/feedback-worker"
@@ -54,7 +54,7 @@ updates:
5454
- "patch"
5555
ignore:
5656
# TypeScript 6.x is a major bump: it deprecates the tsconfig `baseUrl`
57-
# option (TS5101) and breaks the vis/ and web/ builds. Adopting it is a
57+
# option (TS5101) and breaks the dashboard/ and web/ builds. Adopting it is a
5858
# coordinated monorepo migration, not four split bot PRs. Hold the major
5959
# until that lands; minor/patch within the current line still flow.
6060
- dependency-name: "typescript"

.github/workflows/linux-installer.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ jobs:
6262
cache: "npm"
6363
cache-dependency-path: web/package-lock.json
6464

65-
# The web/vis frontends are gitignored build artifacts; without these
65+
# The web/dashboard frontends are gitignored build artifacts; without these
6666
# steps PyInstaller froze a binary whose web UI 404'd on "/". The
6767
# bundles are arch-independent, so they are built once on the host —
6868
# the QEMU container build picks them up from the mounted checkout.
@@ -73,8 +73,8 @@ jobs:
7373
PYTHINKER_WEB_EXPECT_VERSION: ${{ steps.ver.outputs.version }}
7474
run: python3 scripts/build_web.py
7575

76-
- name: Build vis UI bundle
77-
run: python3 scripts/build_vis.py
76+
- name: Build dashboard UI bundle
77+
run: python3 scripts/build_dashboard.py
7878

7979
- name: Set up QEMU (aarch64 only)
8080
if: matrix.qemu

.github/workflows/windows-installer.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ jobs:
6161
cache: "npm"
6262
cache-dependency-path: web/package-lock.json
6363

64-
# The web/vis frontends are gitignored build artifacts; without these
64+
# The web/dashboard frontends are gitignored build artifacts; without these
6565
# steps PyInstaller froze a binary whose web UI 404'd on "/". The spec
6666
# file now also refuses to freeze when the bundles are missing.
6767
- name: Build web UI bundle
@@ -70,8 +70,8 @@ jobs:
7070
PYTHINKER_WEB_EXPECT_VERSION: ${{ steps.ver.outputs.version }}
7171
run: python scripts/build_web.py
7272

73-
- name: Build vis UI bundle
74-
run: python scripts/build_vis.py
73+
- name: Build dashboard UI bundle
74+
run: python scripts/build_dashboard.py
7575

7676
- name: Install PyInstaller
7777
run: uv pip install pyinstaller

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ src/pythinker_code/deps/tmp
2828
# Web build artifacts
2929
src/pythinker_code/web/static/assets/
3030

31-
# Vis build artifacts
32-
src/pythinker_code/vis/static/
31+
# Dashboard build artifacts
32+
src/pythinker_code/dashboard/static/
3333

3434
# Generated reports
3535
.firecrawl/

AGENTS.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@ Development servers:
144144
```bash
145145
make web-back # FastAPI web backend on port 5494
146146
make web-front # web frontend dev server
147-
make vis-back # visualization backend on port 5495
148-
make vis-front # visualization frontend dev server
147+
make dashboard-back # dashboard backend on port 5495
148+
make dashboard-front # dashboard frontend dev server
149149
```
150150

151151
Targeted package commands:
@@ -173,7 +173,7 @@ Pick the smallest reliable gate for the change, then run broader gates before re
173173
| `packages/pythinker-host` | `make check-pythinker-host && make test-pythinker-host` |
174174
| `packages/pythinker-review` | `make check-pythinker-review && make test-pythinker-review` |
175175
| `sdks/pythinker-sdk` | `make check-pythinker-sdk && make test-pythinker-sdk` |
176-
| Web / vis frontends | `make check-web`; build affected frontend when packaging assets changed |
176+
| Web / dashboard frontends | `make check-web`; build affected frontend when packaging assets changed |
177177
| Release / packaging / PyInstaller | `make build` or `make build-bin` as appropriate |
178178

179179
If a gate cannot run because of missing system tools (for example `npm`), report that explicitly
@@ -221,7 +221,7 @@ see `docs/en/customization/architecture.md`. This list is a quick orientation on
221221
- `src/pythinker_code/auth/`: OAuth/API-key provider integrations.
222222
- `src/pythinker_code/background/`: background task worker/runtime support.
223223
- `src/pythinker_code/cli/`: Typer command tree (lazy-loaded subcommands `mcp`, `plugin`,
224-
`skill`, `web`, `vis`, `info`, `export`, `review`, `secscan`, `security-scan`, `debug`,
224+
`skill`, `web`, `dashboard`, `info`, `export`, `review`, `secscan`, `security-scan`, `debug`,
225225
`update`, plus eager `login`, `logout`, `term`, `acp`).
226226
- `src/pythinker_code/hooks/`: hook definitions and execution engine.
227227
- `src/pythinker_code/plugin/`: plugin discovery and installation support.
@@ -239,8 +239,8 @@ see `docs/en/customization/architecture.md`. This list is a quick orientation on
239239
- `src/pythinker_code/tools/`: built-in tools (`agent`, `ask_user`, `background`, `dmail`, `file`,
240240
`plan`, `shell`, `think`, `todo`, `web`, etc.).
241241
- `src/pythinker_code/ui/`: shell, print, and ACP frontends.
242-
- `src/pythinker_code/web/`, `src/pythinker_code/vis/`: backend integrations for web/visualization.
243-
- `web/`, `vis/`: frontend apps bundled into the CLI package.
242+
- `src/pythinker_code/web/`, `src/pythinker_code/dashboard/`: backend integrations for web/visualization.
243+
- `web/`, `dashboard/`: frontend apps bundled into the CLI package.
244244
- `packages/pythinker-core/`: LLM abstraction layer for messages, providers, streaming, and tools.
245245
- `packages/pythinker-host/`: host abstraction for local/remote file and shell operations.
246246
- `packages/pythinker-review/`: review/debug/security engine, code-reviewr-derived PR

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ GitHub Releases page; `0.8.0` is the new starting line.
1515

1616
## Unreleased
1717

18+
- **Agent-tracing dashboard.** Added `pythinker dashboard` — a local web UI for inspecting sessions, wire events, context messages, tool statistics, and usage over time. It is also reachable from the interactive shell via the `/reports` slash command (aliased `/dashboard`).
19+
1820
## 0.44.0 (2026-06-13)
1921

2022
- **Toggle auto-update from the CLI.** Running `/update` now opens a menu — *Check for updates now* (the default, so a bare `/update` + Enter still checks immediately) or *Auto-update on startup* with its current state — so the toggle is discoverable without knowing a subcommand. `/update auto on|off` still sets it directly, and `/update auto` with no value opens an interactive On/Off picker (cursor defaulted to the current setting). The same toggle appears in the interactive `/settings` panel, and `pythinker info` reports the auto-update status. All surfaces show the *effective* state — an external override (`PYTHINKER_CLI_NO_AUTO_UPDATE` or a source checkout) is surfaced as the reason, renders the `/settings` row read-only, and makes `/update auto` report the read-only state rather than popping a no-op picker, so the toggle is never a silent no-op.

Makefile

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ web-back: ## Start web backend with uvicorn (reload enabled).
2929
web-front: ## Start web frontend (vite dev server).
3030
@npm --prefix web run dev
3131

32-
# for pythinker vis development
33-
.PHONY: vis-back vis-front
34-
vis-back: ## Start vis backend with uvicorn (reload enabled).
35-
@LOG_LEVEL=DEBUG uv run uvicorn pythinker_code.vis.app:create_app --factory --reload --port 5495
36-
vis-front: ## Start vis frontend (vite dev server).
37-
@npm --prefix vis run dev
32+
# for pythinker dashboard development
33+
.PHONY: dashboard-back dashboard-front
34+
dashboard-back: ## Start dashboard backend with uvicorn (reload enabled).
35+
@LOG_LEVEL=DEBUG uv run uvicorn pythinker_code.dashboard.app:create_app --factory --reload --port 5495
36+
dashboard-front: ## Start dashboard frontend (vite dev server).
37+
@npm --prefix dashboard run dev
3838

3939
.PHONY: format format-pythinker-code format-pythinker-core format-pythinker-host format-pythinker-review format-pythinker-sdk format-web
4040
format: format-pythinker-code format-pythinker-core format-pythinker-host format-pythinker-review format-pythinker-sdk format-web ## Auto-format all workspace packages.
@@ -145,8 +145,8 @@ cov-pythinker-sdk: ## Run Pythinker SDK tests with coverage.
145145
--cov --cov-report=xml:coverage.xml -vv
146146

147147
.PHONY: build build-pythinker-code build-pythinker-core build-pythinker-host build-pythinker-review build-pythinker-sdk build-bin build-bin-onedir
148-
build: build-web build-vis build-pythinker-code build-pythinker-core build-pythinker-host build-pythinker-review build-pythinker-sdk ## Build Python packages for release.
149-
build-pythinker-code: build-web build-vis ## Build the pythinker-code sdist and wheel.
148+
build: build-web build-dashboard build-pythinker-code build-pythinker-core build-pythinker-host build-pythinker-review build-pythinker-sdk ## Build Python packages for release.
149+
build-pythinker-code: build-web build-dashboard ## Build the pythinker-code sdist and wheel.
150150
@echo "==> Building pythinker-code distributions"
151151
@uv build --package pythinker-code --no-sources --out-dir dist
152152
build-pythinker-core: ## Build the pythinker-core sdist and wheel.
@@ -164,15 +164,15 @@ build-pythinker-sdk: ## Build the pythinker-sdk sdist and wheel.
164164
build-web: ## Build web UI and sync into pythinker-code package.
165165
@echo "==> Building web UI"
166166
@uv run scripts/build_web.py
167-
build-vis: ## Build vis UI and sync into pythinker-code package.
168-
@echo "==> Building vis UI"
169-
@uv run scripts/build_vis.py
170-
build-bin: build-web build-vis ## Build the standalone executable with PyInstaller (one-file mode).
167+
build-dashboard: ## Build dashboard UI and sync into pythinker-code package.
168+
@echo "==> Building dashboard UI"
169+
@uv run scripts/build_dashboard.py
170+
build-bin: build-web build-dashboard ## Build the standalone executable with PyInstaller (one-file mode).
171171
@echo "==> Building PyInstaller binary (one-file)"
172172
@uv run pyinstaller pythinker.spec
173173
@mkdir -p dist/onefile
174174
@if [ -f dist/pythinker.exe ]; then mv dist/pythinker.exe dist/onefile/; elif [ -f dist/pythinker ]; then mv dist/pythinker dist/onefile/; fi
175-
build-bin-onedir: build-web build-vis ## Build the standalone executable with PyInstaller (one-dir mode).
175+
build-bin-onedir: build-web build-dashboard ## Build the standalone executable with PyInstaller (one-dir mode).
176176
@echo "==> Building PyInstaller binary (one-dir)"
177177
@rm -rf dist/onedir dist/pythinker
178178
@PYINSTALLER_ONEDIR=1 uv run pyinstaller pythinker.spec

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -744,8 +744,8 @@ make test-pythinker-sdk # SDK only
744744
```sh
745745
make web-back # web backend
746746
make web-front # web frontend
747-
make vis-back # vis backend
748-
make vis-front # vis frontend
747+
make dashboard-back # dashboard backend
748+
make dashboard-front # dashboard frontend
749749
```
750750

751751
</td>
@@ -770,7 +770,7 @@ make help # all targets
770770

771771
```
772772
pythinker-code/
773-
├── 📦 src/pythinker_code/ CLI runtime · tools · UIs · ACP · MCP · hooks · plugins · skills · web · vis backends
773+
├── 📦 src/pythinker_code/ CLI runtime · tools · UIs · ACP · MCP · hooks · plugins · skills · web · dashboard backends
774774
├── 🧱 packages/
775775
│ ├── pythinker-core/ Provider-agnostic message, tool, and chat-provider abstractions
776776
│ ├── pythinker-host/ Local/remote host filesystem and command execution
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
1-
# Pythinker Vis UI (vis/)
1+
# Pythinker Dashboard UI (dashboard/)
22

33
React 19 + Vite + TypeScript session-tracing visualizer, bundled into the `pythinker-code`
44
package. It is a read-only viewer of Wire events, context messages, agent state, and subagent
55
activity. Run all `npm` commands from this directory.
66

77
## Critical invariants
88

9-
- **`vis/src/lib/api.ts` is hand-written, not generated** (unlike `web/`, which has a generated
9+
- **`dashboard/src/lib/api.ts` is hand-written, not generated** (unlike `web/`, which has a generated
1010
client). Keep its types (`WireEvent`, `ContextMessage`, `SessionInfo`, `SubagentInfo`) in
11-
sync by hand with the vis backend (`src/pythinker_code/vis/`) and the Wire protocol
11+
sync by hand with the dashboard backend (`src/pythinker_code/dashboard/`) and the Wire protocol
1212
(`src/pythinker_code/wire/`) whenever either changes. There is no codegen step here.
13-
- **Do not hand-copy build output.** `scripts/build_vis.py` builds and syncs `vis/dist`
14-
`src/pythinker_code/vis/static`. No ad-hoc copy/rsync scripts.
15-
- **Read-only data plane.** It consumes `/api/vis/*` from the vis backend (port 5495) with a
13+
- **Do not hand-copy build output.** `scripts/build_dashboard.py` builds and syncs `dashboard/dist`
14+
`src/pythinker_code/dashboard/static`. No ad-hoc copy/rsync scripts.
15+
- **Read-only data plane.** It consumes `/api/dashboard/*` from the dashboard backend (port 5495) with a
1616
Bearer token taken from a URL query param; `cache.ts` dedupes in-flight requests. Do not add
1717
write/mutation calls here — mutations belong to the web UI / backend, not the visualizer.
1818

1919
## Stack and conventions
2020

21-
- Build: `tsc -b && vite build`; dev: `npm run dev` (or `make vis-front`). Backend:
22-
`make vis-back` (port 5495).
21+
- Build: `tsc -b && vite build`; dev: `npm run dev` (or `make dashboard-front`). Backend:
22+
`make dashboard-back` (port 5495).
2323
- Styling: Tailwind + Radix UI / shadcn; `react-virtuoso` for efficient large-session lists.
2424
- Feature panels live under `src/features/` (`wire-viewer`, `context-viewer`, `agents-panel`,
2525
`state-viewer`, `sessions-explorer`).

0 commit comments

Comments
 (0)