Files
Ben Taylor 468995e8f5 feat(telemetry): inspector opened event and banner surface split (OSS-566/568) (#6203)
Two related Inspector-telemetry tickets: **OSS-566** and **OSS-568**.

## OSS-566 — explicit "Inspector opened" event

There was no event recording that the panel was opened. Opens could only
be inferred from in-panel activity (~1,655/90d, a floor) or from
`banner_clicked` cta=`body` (~511), which misses the common
floating-button path entirely.

Adds `oss.inspector.opened` with:

| property | values |
|---|---|
| `open_source` | `floating_button` \| `announcement_preview` |
| `has_unseen_announcement` | whether an announcement was on screen at
open time |
| `license_status` / `runtime_mode` / `runtime_url_type` | same
segmentation the threads events already carry |
| `package_name` / `package_version` / `inspector_distinct_id` | version
segmentation |

**Restoring a persisted-open panel deliberately does not count.**
Restore assigns `isOpen` directly instead of routing through
`openInspector()`, so page reloads — and every `next dev` hot reload —
stay out of the number.

## OSS-568 — banner surface + first-class dismissal

1. **`surface` on `banner_viewed`** — `collapsed_preview` (bubble on the
collapsed widget) vs `expanded_card` (card inside the opened panel),
stamped at fire time. Dedup is now per `(banner, surface)` instead of
per banner, so opening the panel records the card impression as its own
signal.
2. **`oss.inspector.banner_dismissed`** — emitted **in addition to**
`banner_clicked { cta: "dismiss" }`, not replacing it, so dashboards
reading the `cta` value keep working. Carries `surface` too, separating
"swatted the bubble away" from "dismissed the card after opening".

Both new events clear the sink's `oss.inspector.` prefix gate, so **no
telemetry-sink deploy is needed**.

## Testing

- **`packages/web-inspector` full suite — 112 passed (4 files)**, run
locally in the worktree:
  ```
   ✓ dev/css-raw-import.spec.ts (1 test) 1ms
   ✓ src/__tests__/telemetry-egress-guard.spec.ts (3 tests) 2ms
   ✓ src/lib/__tests__/telemetry.test.ts (28 tests) 8ms
   ✓ src/__tests__/web-inspector.spec.ts (80 tests) 890ms
   Test Files  4 passed (4)
        Tests  112 passed (112)
  ```
- **New coverage**: payload shape for `opened` / `banner_dismissed`,
incl. an allow-list assertion that no content/PII key can be added
accidentally; collapsed→expanded surface sequence on open; per-surface
dedup; open attribution for both sources; no event for an already-open
panel; no event for a restored-open panel; nothing emitted when the
runtime reports `telemetryDisabled`; an open still recorded while the
runtime is disconnected.
- **`tsc --noEmit`** on `@copilotkit/web-inspector`: clean (after
building `core` + `shared` dist in the worktree).
- **`tsdown` build**: succeeds; the test-only egress-guard helper is
**not** present in `dist/`.
- **`oxfmt --check`**: clean. **`oxlint`**: 9 warnings, all
pre-existing.
- `@copilotkit/runtime` (1,760) and `@copilotkit/shared` (199) also
green — both are back on main's own test files in this PR.

## A test-only egress guard rides along

`vitest.setup.ts` installs a fetch guard that swallows requests to the
telemetry sink. This is **not** CI plumbing — it is a prerequisite for
the new events. These tests run in jsdom, where a real `fetch` exists,
and inspector telemetry is fire-and-forget, so any test that drives a
banner / threads / open path without stubbing fetch POSTs a real
`oss.inspector.*` event to the live sink, from developer machines as
well as CI. The announcement-dismissal tests were already doing this;
the new `opened` / `banner_dismissed` tests hit the same send path. No
environment variable can prevent it, because the inspector's opt-out
arrives in the runtime's `/info` response and these tests never boot a
runtime.

## Not in scope

Suppressing telemetry from CI jobs that boot real apps (**OSS-565**) was
explored on this branch and removed. It needs a mechanism that does not
depend on the `/info` handshake — the env → `/info` → core chain is
asynchronous, so an early interaction beats it. That ticket stays open
and unaddressed here.

Closes OSS-566, OSS-568.
2026-07-31 08:33:57 -05:00
..
2026-04-10 23:38:59 +00:00
2026-07-28 17:48:23 -07:00

@copilotkit/web-inspector

Standalone Thread Inspector QA

Run the shared inspector without an app shell:

pnpm nx run @copilotkit/web-inspector:dev:standalone

Open http://127.0.0.1:5177/.

Validation steps:

  1. Confirm the initial AG-UI events scenario opens on the Timeline tab and renders run, message, and tool rows.
  2. Click Messages only and confirm the first-visible Timeline renders persisted message content instead of an empty Timeline.
  3. Click Raw event only and confirm the Timeline renders a THREAD_STATE_WRITTEN row with a source-event link.
  4. Use a Timeline source-event link and confirm it opens the Raw AG-UI Events tab on the corresponding event.
  5. Open the State tab and confirm the demo state is visible.

This harness uses demo provider data only. Manual product validation for Intelligence-backed threads still needs a real Intelligence backend.