The in-header thread-drawer launcher toggles `drawerOpen`, which only drives the
off-canvas MOBILE drawer; on desktop the drawer is a persistent in-flow panel
that ignores `open`, so the launcher was a dead no-op there (it appeared to do
nothing on click). Gate it on a reactive mobile viewport check so it renders
only at ≤767px. On desktop the chat's own open/close — the toggle FAB + the
header close (both lucide X) — is the consistent pair; nothing masquerades as a
chat control.
CopilotChatConfigurationProvider treated any `threadId` prop as controlled, so
the auto-minted non-explicit threadId that <CopilotKit>'s v1 bridge seeds
blocked the drawer's imperative setActiveThreadId/startNewThread — thread
switching and "+ New" were dead in every app wrapped in <CopilotKit>. A
non-explicit (`hasExplicitThreadId={false}`) threadId is now overridable; a
genuine caller-supplied threadId stays controlled.
Also, surfaced during the langgraph-js de-fork validation:
- CopilotChat clears messages when switching to a fresh non-explicit thread
("+ New") so the welcome screen shows instead of the prior thread — including
when a still-loading /connect is superseded by the switch.
- CopilotDrawer treats a pending (null) license status as loading, not
unlicensed, so the upgrade upsell no longer flashes or sticks before the
runtime reports the license.
Add an optional onAction interceptor to createA2UIMessageRenderer so apps
can handle A2UI actions client-side (e.g. navigate) instead of forwarding
every action to the agent.
- onAction(action, forward) runs before forwarding. Return null to handle
client-side and stop forwarding, return a modified action to forward it,
or return undefined to forward unchanged.
- Threaded from createA2UIMessageRenderer options through ReactSurfaceHost.
- Extracted runA2UIAction helper for deterministic unit testing.
- Default behavior is unchanged when onAction is not supplied.
Add <CopilotDrawer> (interops with the shadow-DOM element, two-pronged license
gate, scoped chat-input focus return, registration-gated header launcher) and
extend CopilotChatConfigurationProvider with drawerOpen + mobile mutual
exclusion + a non-explicit active-thread setter so a bare drawer connects to the
picked thread and resets on New with no host wiring. useThreads gains an
{enabled} gate and a list-only error channel.
Fixes#5635.
## What
Headers set directly on an `HttpAgent` registered via
`agents__unsafe_dev_only` were silently replaced by the provider
headers. Per-agent auth headers (like an `Authorization` for a
self-hosted backend) got dropped, causing 401s.
## Why
`AgentRegistry.applyHeadersToAgent` did `agent.headers = {
...core.headers }`, a full overwrite. The run handler and the react-core
`useAgent` hook did the same. So an agent built with its own headers
lost them on registration, on every `setHeaders`, and before each
request.
## Fix
Merge instead of replace. The registry captures each agent's own headers
once (in a WeakMap, before the first apply) and rebuilds `{
...ownHeaders, ...coreHeaders }`. Core wins on key conflicts, which
keeps the existing "provider headers are authoritative" and logout/clear
behavior. All header application now routes through one method,
`CopilotKitCore.applyHeadersToAgent`, so runs never clobber per-agent
headers.
Vue and Angular benefit too: they dispatch runs through `core.runAgent`
/ `connectAgent`, so the merge is re-applied before every request.
## Tests
- core: 3 new cases in `core-headers.test.ts` (preserve, merge,
retain-across-setHeaders); existing overwrite and clear tests still
pass.
- react-core: new `use-agent-provider-headers.e2e.test.tsx` with a real
provider and an HttpAgent that has its own headers.
Verified locally: format, lint, full core + react-core suites, and both
builds.
## Summary
Adds `unarchiveThread(id)` to the v2 thread store (`@copilotkit/core`)
and the `useThreads` hook (`@copilotkit/react-core/v2`), restoring an
archived thread via the existing generic `PATCH /threads/:id { archived:
false }` update path — no new runtime endpoint. Mirrors `archiveThread`
across the store and hook.
This is the durable, architecture-independent piece extracted from the
threads-drawer effort. The drawer UI itself is being restarted as a
framework-agnostic **CopilotDrawer** (Lit web component + React/Angular
wrappers) under a separate spec; this hook method stands on its own and
is needed regardless.
## Testing
TDD. New core store test (`PATCH … { archived: false }`) and
`useThreads` hook test; full suites green (core, react-core).
Restores an archived thread via the existing generic PATCH /threads/:id
update path with { archived: false } — the same mechanism example apps
already use for restore — so no new runtime route is required. Mirrors
archiveThread across the core thread store and the v2 useThreads hook.
Repairs TypeScript check-types across the monorepo and adds a CI gate so
regressions are caught going forward:
- core: bundler module resolution and strict-mode fixes
- sdk-js: bundler module resolution; keep codegen, formatter, packaging working
- react-core: fixes across components, hooks, and tests
- react-native: restore catch binding referenced by TypeError cause
- runtime: repair check-types and bound AI SDK schema inference
- web-inspector: nodenext import extensions, export Anchor
- remaining packages and node example: assorted check-types repairs
- deps: add missing type-only devDependencies
- license context driven from /info licenseStatus
- ci: run check-types in the static quality workflow
Squashed from 12 commits for a single, easily-revertable change.
CR round 2 follow-ups (no behavior change):
- Add a core-headers regression test proving the agentOwnHeaders baseline
stays pristine across remove + re-add (the WeakMap is intentionally not
cleared on removal; clearing would re-capture polluted headers).
- Correct the stale `headers` config doc ("appended" -> merged on top of each
HttpAgent's own headers, core wins).
- Tighten the e2e no-provider-headers assertion to toEqual.
## Summary
- Mint a GitHub App token for the stable release workflow and reuse it
for PR creation and follow-up API calls
- Disable lefthook during automation commits so release PR generation
does not depend on local developer hooks
- Relax the CopilotChat perf regression test to assert correctness
without a hard 5s wall-clock check
## Testing
- Unit/UI test updated to allow longer async rendering while still
verifying 100 messages render successfully
- Not run (not requested)
CR round 1 follow-ups (no behavior change):
- Document on setHeaders + applyHeadersToAgent that the merge baseline is the
agent's construction-time headers, so setHeaders can override but cannot
remove a per-agent header (the agent's own value re-surfaces on clear), and
that dynamic updates go through setHeaders, not direct agent.headers mutation.
- Tighten the agentOwnHeaders field comment (captured on first apply, never
re-captured) and the applyHeadersToAgent method doc.
- Add a core-headers test pinning the clear-reveals-baseline contract.
- Soften the two useAgent test-mock comments: they are an additive stand-in,
not a faithful model of core's frozen baseline.
Adds the AG-UI standard interrupt flow (RUN_FINISHED outcome:interrupt + resume array) alongside the legacy on_interrupt path.
- core: forward the standard resume array through runAgent.
- react-core / vue / react-native: useInterrupt handles standard interrupts with resolve()/cancel(), surfaces the primary + full interrupt set, and persists each resolved tool-backed interrupt as a tool-result message so multi-turn conversations stay well-formed (no dangling tool call -> no tool-call loop).
- runtime BuiltInAgent: native interrupts for the aisdk + tanstack factory paths via each SDK's needsApproval primitive (tool-approval-request / CUSTOM approval-requested -> outcome:interrupt); classic interrupt-tool emission + ctx.interrupt() factory primitive; idempotent resume injection mapped to each SDK's native tool-result; getCapabilities advertises humanInTheLoop.interrupts.
- docs: document standard interrupt support.
Verified across core/react-core/runtime unit suites and a real-model multi-turn run on both aisdk and tanstack.
HttpAgent headers configured directly on an agent registered via
agents__unsafe_dev_only were silently replaced by core headers, dropping
per-agent auth headers and causing 401s against self-hosted backends.
Core headers are now merged ON TOP of each agent's construction-time
headers (captured once in a WeakMap before the first apply), with the
core-level value winning on a key conflict. Header application is
centralized in CopilotKitCore.applyHeadersToAgent so the run handler and
the react-core useAgent hook share one merge path and never clobber
per-agent headers.
A catalog on <CopilotKit a2ui={{ catalog }}> is now enough to use A2UI
end to end. Previously developers also had to set a2ui.injectA2UITool: true
on the runtime.
The provider forwards an a2uiCatalogAvailable signal per run whenever it has
a catalog (and renders surfaces locally). handle-run reads that signal and
hands it to configureAgentForRequest, which enables A2UIMiddleware and defaults
injectA2UITool to true. An explicit injectA2UITool value (including false) and
an explicit a2ui.enabled: false are always respected via ?? / short-circuit, so
this only fills the default and never overrides a deeper opt-out.
setHeaders typed headers as Record<string, string>, so there was no
type-safe way to clear a header (e.g. Authorization on logout) — passing
an empty string left the header present with a blank value.
Widen the signature to Record<string, string | null | undefined> and drop
any entry whose value is null/undefined. setHeaders remains a full overwrite,
so clearing one header while keeping the rest is the spread pattern:
setHeaders({ ...copilotkit.headers, Authorization: null }). A shared
normalizeHeaders helper enforces the same string-only invariant at both
write paths (constructor and setHeaders).
Update the react-core AuthTokenSync skill example to show the logout/clear
path and warn that a header must not be managed via both the headers prop and
imperative setHeaders (the provider re-applies prop-derived headers as a full
overwrite when its inputs change). Also update the setHeaders reference
signature docs. Tests cover null/undefined stripping, empty-string
preservation, overwrite-not-merge semantics, single-header clear via spread,
subscriber notification, and propagation to local and remote
(ProxiedCopilotRuntimeAgent) agents.
Fixes#5535
Strengthen the license-signal test so it pins that selfManagedAgents
satisfies hasLocalAgents — the Enterprise warning fires while the
separate "Missing required prop" missing-runtime warning does not.
Refs #5417
selfManagedAgents is part of CopilotKit's Enterprise Intelligence
offering. Emit an advisory console.warn (in both development and
production) when it is supplied without a publicLicenseKey/publicApiKey,
so production usage is surfaced. The signal is client-side and not
enforced — rendering still proceeds — and agents__unsafe_dev_only
remains a free local-dev escape hatch.
Refs #5417
Clear the console.error spy inside the render helper so each assertion
is independent, and split the combined runtimeUrl/publicApiKey case into
two tests so each renders a single provider tree.
Refs #5417
Add empty-map (selfManagedAgents={}) throw case and the pre-existing
runtimeUrl/publicApiKey happy paths so a future gate inversion is
caught, and assert valid configs surface no unexpected console errors
instead of blanket-silencing console.error.
Refs #5417
The v1 <CopilotKit> wrapper's validateProps threw ConfigurationError
whenever neither runtimeUrl nor a public key was supplied, ignoring
self-managed agents. This rejected the documented self-managed-agent
setup even though the underlying v2 CopilotKitProvider accepts it.
Mirror the provider's hasLocalAgents gate so selfManagedAgents and
agents__unsafe_dev_only satisfy the check.
Closes#5417
Extend the unscoped-tool attribution test to verify toolCallId persists and
agentId stays undefined after the tool moves InProgress -> Executing, not just
at InProgress.
Code-review follow-up. Replace the unreachable `as any` fallback branch with
a compile-time exhaustiveness check (const _: never = props): a newly-added
ToolCallStatus now becomes a type error that must get its own branch, rather
than silently rendering with respond=undefined. Also correct the prop-build
comment (name/description are overwritten with the registration values, not
'normalized'). No behavior change for the three live statuses.
Addresses code-review findings on the HITL attribution change:
- Correct the render-prop JSDoc: agentId is the tool's STATIC registration
scope (undefined for unscoped tools), not the runtime sub-agent; toolCallId
is the key to correlate with runtime attribution (onToolExecutionStart /
event stream). Removes the over-claim that agentId resumes 'the correct
sub-agent'.
- Compare props.status against the ToolCallStatus enum instead of string
literals (removes silent drift risk).
- Inject name/description/agentId in the otherwise-unreachable fallback branch
so attribution is never silently dropped if a status is ever added; cast
the narrowed-never props to a record so the spread typechecks.
Behavior-preserving for the three live statuses; e2e suite green (13/13).