Review found two gaps in the previous commit.
`RunAgentInput.context` never reached the model. The bridge puts it on state
under `context`, but `CopilotKitState` does not declare the field, so pydantic
drops it when the endpoint validates the request into the Flow's state and the
"Application context" block rendered without it. That hollowed out the two cells
whose whole point is reading application context: readonly-state-agent-context
(now on the default `/chat` route) and agent-config. `ChatState` declares the
field so it survives validation.
Neither existing test caught it: the readonly probe only asserts the browser
request body carries its sentinel, the agent-config probe encodes the expected
value in the user message, and Flow-level unit tests bypass endpoint state
initialization. The new endpoint test drives the real FastAPI route with two
context entries and asserts both appear in the model's system message; it fails
without the declared field.
The Channels setup fragment still told readers the shared crew sits at the
server root and set `AGENT_URL` accordingly, which the removed catch-all turned
into a dead endpoint. It now points at `/chat` and says Flow rather than crew.
Migrating the consumer was preferred over restoring `/`, which would put the
silent-fallback trap back in place.
Verified: 164 and 166 Python tests pass across the two columns, the docs
setup-content tests pass (16), and readonly-state-agent-context, agent-config
and agentic-chat are green on D6 replay.
## Summary
- complete the tool-only HITL approval leg when the app-level approval
modal mounts
- retain the shared runner's finished-run/new-assistant-bubble gates and
the existing approval/follow-up assertions
- add a contract test that pins the modal completion selector to the
first turn
## Why
Unhandled tool calls intentionally render no default chat card. The HITL
fixture's first leg therefore produces an empty assistant bubble plus
the approval modal, so text-stability completion cannot converge even
though the app and fixture are healthy.
## Verification
- focused red/green contract: 8 tests passed after failing on missing
`completeOnMount`
- showcase harness: 177 test files / 3,722 tests passed; typecheck and
build passed
- isolated fleet-control-plane D5 cells passed for LangGraph Python,
CrewAI Conversational Flows, and Mastra
## Deployment scope
This changes only the shared showcase harness image. Promote the harness
control-plane and harness pool-worker roles together; no integration
service image changes are required for this fix.
## Summary
Redesigns the Web Inspector around Home, What's New, System Health,
Intelligence, and a clearer responsive sidebar. It also keeps live
Threads scoped to the matching agent so All Agents does not show
duplicates.
## Why
The Inspector needed a faster at-a-glance health view, coherent light
and dark themes, explicit Intelligence states, and a notification flow
that fits the new animated launcher without showing a floating banner
over the host application.
## How
- adds Alem Tuzlak's Home briefing, live sidebar, and matching-agent
thread filtering
- integrates the latest launcher halo, pulse, and unread dot from main
- opens unread launcher notifications on Home with a What's New preview
and sidebar ping
- marks the announcement read only after its What's New content is
visible
- adds responsive System Health, Intelligence, features, Learning,
Settings, and What's New surfaces
- expands the deterministic local test bench, including disconnected
Intelligence and RUN_ERROR states
- preserves Alem's original authored commits and keeps the follow-up
polish in one Tyler-authored commit
## Verification
- pnpm nx test web-inspector --skip-nx-cache (481 tests)
- pnpm nx build web-inspector --skip-nx-cache
- full pre-commit affected package test, publint, and attw checks
- interactive launcher-to-dismissal walkthrough in the local Inspector
lab
## Related
- Linear: OSS-866
- Linear: OSS-868
REST /threads is agent-scoped. The Phoenix user_meta channel is not. Drop live upserts whose agentId does not match the store so Inspector All Agents does not show the same thread twice.
After the first chat, web quickstarts now tell the reader to open
Inspector and confirm three things: the agent is listed, AG-UI Events
are moving, and Threads is unlocked or shows Enable Intelligence.
## What does this PR do?
- Add a shared Open Inspector step after the first chat in every web
integration quickstart, plus Vue and Angular.
- Angular links the [Inspector for Angular](/angular/inspector) install
page first. Vue sets `show-dev-console="auto"` so the overlay appears on
localhost.
- Add a short Callout on feature pages that map to a shipped pane:
Threads, Frontend Tools, State, Context, Learning, and HITL tools.
- Add the `inspector-docs` skill so a new Inspector pane gets a docs
pointer, or `no page yet`.
- Keep the Intelligence signup copy that names Inspector. Skip React
Native and Channels.
## Related PRs and Issues
- Linear: https://linear.app/copilotkit/issue/OSS-885
## Checklist
- [ ] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation
- [x] "Allow edits by maintainers" is checked (lets us help iterate on
your PR directly — faster turnaround for everyone)
## Testing
Commands run:
1. File contract check against the shared step, 17 integration
quickstarts, Vue, Angular, feature Callouts, and non-web skip. Passed.
2. `node --experimental-strip-types scripts/sync-plugin-skills.ts
--check`. Passed (`plugin skill mirror in sync`).
3. Did not run `pnpm test` or shell-docs `vitest`. This worktree has no
`node_modules`.
Manual test:
1. Follow a React quickstart on localhost. After the first chat, open
Inspector. Agents lists the agent. AG-UI Events move. Threads is
unlocked or shows Enable Intelligence.
2. Repeat with Intelligence set to No. The Open Inspector step is still
there. Threads shows Enable Intelligence.
3. Follow the Angular frontend guide. The step links the Angular
Inspector install page first.
4. Open Threads, frontend tools, shared state, and agent-readonly. Each
has a Callout that names the matching pane.
How this PR makes testing easy:
`showcase/shell-docs/src/lib/__tests__/inspector-docs.test.ts` fails if
a web quickstart drops the step, if a mapped feature page drops its
Callout, or if Callouts name Playground or Fork.
## Risk / rollback
Docs-only plus a repo skill. Revert the PR to undo. No runtime API
change.
## Summary
- register the provisioned `showcase-crewai-conversational-flows`
production Railway service instance, domain, health path, and probe in
the Railway SSOT
- regenerate the promotion closure and workflow service selector so the
integration can be promoted through the standard runbook path
- update SSOT, image-reference, generator, and environment-aware
redeploy tests for dual-environment coverage
- recast the staging-only runbook reference as a completed
staging-to-production example
This deliberately does not mark the integration manifest as deployed or
perform another Railway mutation. It only reconciles the already-running
production instance into source control.
## Live verification
- production `/api/health` returns HTTP 200
- production and staging run the same image digest:
`sha256:e6f38a9454f8ae9410239bb3cc75d21b0d2ccecbbbfe789b25a9f2d9f03139b4`
- all 84 environment-scoped Railway image refs verified
- `autoUpdates` verified disabled across all 84 service/environment
checks
- promotion dry-run resolves the production target to the pinned digest
above
## Local verification
- `pnpm exec tsc --noEmit -p showcase/scripts/tsconfig.json`
- uncached Nx test run: 77 files, 2,519 tests passed
- Railway Ruby suite: 188 runs, 723 assertions passed
- `pnpm lint` (0 errors)
- `actionlint .github/workflows/showcase_promote.yml`
- `pnpm exec tsx showcase/scripts/emit-railway-envs-json.ts --check`
- `pnpm exec tsx showcase/scripts/sync-promote-service-options.ts
--check`
## Summary
Replace the Inspector announcement banner with a non-blocking unread
signal on the launcher and a persistent **What's new** destination
inside the Inspector. The launcher now uses the approved responsive Kite
treatment: an internal wash plus two visible, staggered water-ripple
rings.
This follow-up also trims the implementation to the one signal that
exists today, adds a local replay control, and records when the launcher
notification is actually presented.
## Why
The old banner covered the host application and duplicated the
announcement inside every Inspector tab. The initial signal
implementation also carried speculative registry machinery for future
error notifications, could consume its only pulse while the launcher was
hidden, and counted ordinary announcement-content clicks as CTA
interactions.
The notification funnel also had no exposure event, and announcement
telemetry could run before the runtime handshake revealed that telemetry
was disabled.
## How
- Adds **What's new** as the first primary navigation destination and
removes the host-app overlay.
- Uses direct news-signal state instead of a generic one-entry registry.
- Defers the one-beat pulse until the launcher and browser tab are
visible, and persists read state only after announcement content
renders.
- Adds `oss.inspector.whats_new_signal_viewed`, emitted once per
announcement presentation with `banner_id`, `surface: "launcher"`, and
`presentation: "animated" | "reduced_motion"`.
- Holds notification views and attribution behind the runtime `/info`
handshake, preventing events or `posthog_distinct_id` link parameters
when telemetry is disabled.
- Tracks announcement clicks only when a link is activated.
- Scales the launcher from 51.84 px on compact screens to a 62.208 px
desktop cap, with an internal wash, two staggered outward ripples, a
resting unread dot, and a reduced-motion fallback.
- Preserves the Kite artwork and pins its crop/path invariant in tests.
- Adds a one-shot **Replay notification** workbench control that
preserves Inspector layout and clears only the local read/pulse mirrors
needed for replay.
- Keeps the launcher pointer cursor at rest and the grabbing cursor only
while dragging.
Verified with 463 Web Inspector tests plus Nx type-check and build
targets. The full pre-commit test, package-quality, publint, and `attw`
gate passes; lint reports zero errors.
Related: OSS-860, OSS-864, OSS-865
- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] Relevant documentation is updated
- [x] Allow edits by maintainers is enabled
Replace speculative signal machinery with direct state and defer hidden pulses.
Limit click telemetry to real links and add the replay workbench control.
Restore the pointer cursor and record visible launcher presentations.
Add host-scoped read state and the persistent What’s new destination.
Include the responsive Kite treatment, renamed announcement telemetry, and complete behavior tests.
Refs OSS-860, OSS-864, OSS-865
Track the started input through protocol errors so remapped run IDs clean up
the active run without disturbing pre-start failures. Add lifecycle and
multi-call reconciliation coverage.
Reconcile streamed tool results by call identity so divergent message IDs
cannot append a second real result. Share placeholder normalization between
state reconciliation and run-handler forwarding.
Moves all 239 showcase integration routes off
`copilotRuntimeNextJSAppRouterEndpoint`, the deprecated v1 Next.js adapter, so
the v1 entrypoint has no remaining code-level users under
`showcase/integrations/`.
const copilotHandler = createCopilotRuntimeHandler({
runtime,
basePath: "/api/copilotkit-x",
mode: "single-route",
});
...
return await copilotHandler(req);
## Why single-route, and why this handler
**Single-route** because these demos' frontends are
`<CopilotKit runtimeUrl="/api/copilotkit-x">` with no transport prop, and every
released provider pins the single-route transport. Single-route mode is
therefore a drop-in for the v1 adapter: no frontend change, no path change, no
`GET` export, and nothing here probes `/info`. Migrating to multi-route instead
would have required editing every demo page in lockstep for no functional gain.
**`createCopilotRuntimeHandler`** rather than `createCopilotEndpointSingleRoute`
because that helper is itself deprecated in favour of the `mode` option (see the
deprecated-aliases table in `docs/backend/runtime-endpoints.mdx`), and because
the fetch handler needs no `hono` dependency and composes directly with the
wrappers these routes already have.
The statement is rewritten in place, inside whatever wrapper it already sat in,
so `withForwardedHeaders`, the try/catch envelopes, `wrapStreamingResponse` and
`withCvdiagBackend` are all untouched. 75 of these routes construct the runtime
inline in the call; rewriting in place preserves that per-request construction
exactly as v1 did. No `runner` is added — it is optional, and none of these
routes passed one before.
13 `copilotkit-auth/[[...slug]]` routes already use the v2 fetch handler and are
left alone; they only mention the v1 name in explanatory comments.
## Collateral
- `mastra`'s main route declared a module-level
`const serviceAdapter = new ExperimentalEmptyAdapter()` plus a startup log
about the adapter choice. V2 has no service adapters, so both are gone and the
comment now explains that there is nothing to configure.
- The three `mastra` vitest suites mocked `@copilotkit/runtime` and the v1
`{ handleRequest }` return shape; they now mock `@copilotkit/runtime/v2` and
`createCopilotRuntimeHandler`, which returns the handler directly.
- 27 `@ts-expect-error` directives guarded the **v1** `CopilotRuntime` agents
type ("wraps Record in MaybePromise<NonEmptyRecord<...>>"). Under `/v2` that
hole is gone, which makes the directive unused — a hard error. They are
demoted to `@ts-ignore`, which compiles whether or not the mismatch survives
in a given integration, because 19 of these apps cannot be built locally to
prove it either way. Removing all ~220 now-stale suppressions is left as
follow-up once CI has built every integration green.
## Verified
`mastra` is the one integration installed and exercised locally (19 routes, the
`withCvdiagBackend` main route, and the only vitest suites that touch routes).
Measured against `origin/main` in the same tree:
tsc --noEmit baseline: errors in 10 files
after: errors in 9 files
new errors introduced: NONE
fixed: src/app/api/copilotkit-mcp-apps/route.ts, whose
@ts-expect-error was ALREADY unused on main
vitest run baseline: 2 files failed, 13 tests failed, 21 passed
after: 2 files failed, 13 tests failed, 21 passed
→ test-neutral; those 13 failures are pre-existing on main
Structural audit over all 239 routes: none still imports the v1 root, uses the
v1 adapter, references `ExperimentalEmptyAdapter` or `handleRequest` in code, or
is missing `createCopilotRuntimeHandler` / `basePath` / `mode: "single-route"`.
The shape itself was proved end-to-end before the rollout, in a real running
app with an untouched provider (aimock as the model backend):
`POST /api/copilotkit` -> 200 twice, chat turn rendered.
## Two pre-existing problems found on the way
- `npm ci` fails in `showcase/integrations/mastra`: `Missing:
@types/http-errors@2.0.5 from lock file`. Its Dockerfile uses
`npm ci --legacy-peer-deps`, which does succeed, so the image still builds —
but a plain `npm ci` does not. Untouched here; no manifest or lockfile is in
this diff.
- `mastra`'s vitest suite is red on `main` (13 failures, mostly
`extractXHeaders` dereferencing `req.headers` on a `{}` fake request).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
## Summary
- replace the configuration-context update in the assistant slot-prop
stability test with an unrelated message-view prop update
- preserve coverage that the raw-event feedback adapter does not churn
ordinary assistant render props
- leave production behavior and the callback-only raw-event boundary
unchanged
## Root cause
The test changed chatInputPlaceholder, which changes the memoized
chat-configuration context value. CopilotChatAssistantMessage consumes
that context, so React correctly rerenders it independently of the
message-view memo comparator. The configuration update was therefore not
an unrelated proxy for feedback-adapter churn.
## Test plan
- [x] reproduce the original expected 1 / received 2 failure
- [x] prove the corrected test fails when className is temporarily added
to the feedback adapter memo dependencies
- [x] raw-event feedback test file
- [x] React-core memoization/performance tests
- [x] complete React-core suite on React 19
- [x] complete React-core suite on React 18 compatibility overrides
- [x] React-core build and normal typecheck
- [x] changed-file format and lint checks
Swapping the create_agent factory for create_react_agent (langgraph.prebuilt)
does not work: create_react_agent has no middleware= or system_prompt=
parameter and rejects state_schema=CopilotKitState, so following the comment
raises TypeError. It is also deprecated in favour of langchain.agents.create_agent.
Replace the misleading inline comment with an accurate note at all 7 sites
(supersedes the deprecated factory; accepts neither middleware= nor
system_prompt=), and fix the TypeScript snippets to reference createReactAgent
instead of the Python snake_case name.
Closes CopilotKit#6607
The "Sort out my offsite expenses" beat had three problems on stage: the
harness console was a black slab in a light-mode transcript, the tool
activity grew a stack of finished steps that pushed the report card off
the screen, and the run took a full minute.
## Console (banking skin)
- Every colour is now a semantic token, so the pane follows the app into
dark or light. It was `bg-ink` with `text-white/45`-style overlays,
which only ever looked right in one mode.
- **Collapsed by default.** The status strip still carries the live
state ("3 agents working"), so the run reads as alive while closed.
- Still the **full** log when open. It is the detail view, and windowing
it as well left two lines and nowhere to read the rest.
## Tool activity (shell, affects all skins)
- Rolls to the last two lines; older ones are **removed**, not
collapsed.
- Registration is a **layout** effect, and that is load-bearing. A new
line renders before it is registered, and registering is what evicts the
oldest, so with a passive effect the browser painted the in-between
state: three rows for one frame on every tool call, and again when the
end-of-run `MESSAGES_SNAPSHOT` remounts every line at once. Measured per
animation frame over a full run — 12,734 frames, never more than two,
one `1->2` transition.
- A shared registry rather than something simpler because CopilotKit
renders one component per tool call and owns the container. CSS
`:nth-last-child` needs siblings and the lines had one parent each;
mount-order counters drift across the snapshot remount.
Reviewers should know this one is **not** scoped to banking. Most beats
emit one or two tool calls so it is a no-op for them, but a beat
emitting three or four would now show only its last two.
`VISIBLE_TOOL_ACTIVITY` is a single constant if we want it higher.
## Agent: 1m 0s -> ~45s
- **Research is gated on the offsite dates.** A charge dated outside the
window is settled by its date whatever the merchant turns out to be, so
half the researcher dispatches were buying nothing. Travel on the
adjacent days is still kept in scope.
- **Filings go out in one command** instead of one `curl` per row. The
researchers already ran concurrently, so halving them bought almost
nothing — the serial per-row round-trips through the model were most of
the wall clock.
- Fetch and verify are one command; there is nothing to decide between
the halves.
- Analyst reasoning effort defaults to `medium`, overridable with
`BANKING_EXPENSE_EFFORT`.
## Filing is idempotent
The batching made this necessary rather than optional: the script got
run twice and every charge was filed twice, so the report card claimed
six filings while the ledger held twelve. A duplicate here is a
reimbursement claimed twice.
The script now writes `filed.json` and exits early if it already exists.
That marker is cleared once per run, because the workspace is a fixed
directory shared by every run and a stale marker would convince the next
demo it had already filed and post nothing at all — the same bug wearing
the opposite mask, and a quieter one, since a run that files nothing
still writes a confident report.
Deduping server-side on merchant+amount would have been wrong: **Hotel
Verrano legitimately appears twice at the identical $318.55** for the
two nights of the offsite.
## Verification
Run against a live Intelligence stack, not unit tests alone:
- Six rows filed, all `status=pending`, stable across 60s of polling.
- Present in the Pending Approval queue with their notes and
approve/decline actions.
- Report card: 14 rows read, 6 merchants researched, $2,377.15
reimbursable.
- Console checked in both themes (panel `#f9f8fc` light / `#1f1c2c`
dark, text inverting with it).
`lint`, `typecheck`, `test:unit` (2460 passed) and `build` all green,
re-run after rebasing onto current main.
Does this change make anything in `.claude/skills/reskin/` wrong,
incomplete, or misleading? No — nothing there documents the harness
console, the tool-activity renderer, or the analyst prompt.
The "Sort out my offsite expenses" beat had three problems on stage: the
harness console was a black slab in a light-mode transcript, the tool
activity grew a stack of finished steps that pushed the report card off
the screen, and the run took a full minute.
Console (banking skin):
- Every colour is now a semantic token, so the pane follows the app into
dark or light instead of being hardcoded dark. It was `bg-ink` with
`text-white/45`-style overlays, which only ever looked right in one mode.
- Collapsed by default. The status strip still carries the live state, so
the run reads as alive while closed.
- Still the FULL log when open. It is the detail view, and windowing it as
well left two lines and nowhere to read the rest.
Tool activity (shell, all skins):
- Rolls to the last two lines; older ones are REMOVED, not collapsed.
- Registration is a layout effect, and that is load-bearing. A new line
renders before it is registered, and registering is what evicts the
oldest, so with a passive effect the browser painted the in-between
state: three rows for one frame on every tool call, and again when the
end-of-run MESSAGES_SNAPSHOT remounts every line at once. Measured per
animation frame over a full run: 12,734 frames, never more than two.
- A shared registry rather than something simpler because CopilotKit
renders one component per tool call and owns the container. CSS
`:nth-last-child` needs siblings and the lines had one parent each;
mount-order counters drift across the snapshot remount.
Agent (run time 1m 0s -> ~45s):
- Research is gated on the offsite dates. A charge dated outside the
window is settled by its date whatever the merchant turns out to be, so
half the researcher dispatches were buying nothing. Travel on the
adjacent days is still kept in scope.
- Filings go out in one command instead of one curl per row. The
researchers already ran concurrently, so the serial per-row round-trips
through the model were most of the wall clock, not the research.
- Fetch and verify are one command; there is nothing to decide between
the halves.
- Analyst reasoning effort defaults to medium, overridable with
BANKING_EXPENSE_EFFORT.
Filing is idempotent, which the batching made necessary: the script got
run twice and every charge was filed twice, so the report card claimed six
filings while the ledger held twelve. The script now writes `filed.json`
and exits early if it exists. That marker is cleared once per run, because
the workspace is a fixed directory shared by every run and a stale marker
would convince the next demo it had already filed and post nothing at all
— the same bug wearing the opposite mask, and a quieter one, since a run
that files nothing still writes a confident report.
Deduping server-side on merchant+amount would have been wrong: Hotel
Verrano legitimately appears twice at the identical 318.55 for the two
nights of the offsite.
Does this change make anything in .claude/skills/reskin/ wrong,
incomplete, or misleading? No. Nothing there documents the harness
console, the tool-activity renderer, or the analyst prompt; its only
matches for "console" are `console.error` in unrelated template code.
Verified on the real path against a live Intelligence stack: six rows
filed, all status=pending, stable across 60s of polling, and present in
the Pending Approval queue with their notes and approve/decline actions.