Commit Graph

12905 Commits

Author SHA1 Message Date
Tyler Slaton 97058dc00f docs(shell-docs): update Slack and Teams agent framing (#5789)
## Summary

- Backport the website messaging from CopilotKit/website#398 into the
shell-docs Slack and Microsoft Teams frontend pages.
- Replace the stale waitlist/managed-only framing with "get early
access" copy that presents CopilotKit Enterprise Intelligence as the
self-hosted or cloud-hosted production layer around the open source Bot
SDK.
- Frame Slack and Teams as frontends for agents built on any harness or
framework, while reserving production-layer terminology for CopilotKit
Enterprise Intelligence.
- Address browser review annotations on both pages: remove filler in the
opener, avoid setup-heavy lead copy, use "open source" without a hyphen,
add the full CopilotKit Enterprise Intelligence name to the CTA titles,
and keep CTA telemetry surfaces intact.
- Update the shell-docs nav test expectation so it matches the current
root IA, where Threads lives under Build Chat UIs rather than the
generated Intelligence Platform section.

## Validation

- `npm run lint` from `showcase/shell-docs` (passes with existing
warnings)
- `npm run typecheck` from `showcase/shell-docs`
- `npm run test` from `showcase/shell-docs`
- `npm run build` from `showcase/shell-docs`

## Notes

- Hydrated Git LFS assets locally with `git lfs pull` so the shell-docs
public asset tests could read real PNG bytes.
2026-07-08 09:54:30 -07:00
David McKay 5245634c62 chore(banking): add stop-demo.sh teardown companion to run-demo.sh (#5877)
## What

Adds `examples/showcases/banking/stop-demo.sh` — the teardown companion
to the existing `run-demo.sh`.

## Why

`run-demo.sh` detaches everything except the Next.js dev server:

- `docker compose up -d --wait` (detached stack)
- native Metal TEI via `nohup … & disown` (Apple Silicon only)
- `exec pnpm dev` (the only foreground process)

So Ctrl-C stops *only* the dev server and silently leaves the docker
stack (`banking-memory`) and the host embedder on `:7067` running. There
was no one-command way to bring those down. This script fills that gap
and mirrors `run-demo.sh`'s conventions (same `say`/`ok` helpers, same
header-comment style, idempotent).

## What it does

Tears down, idempotently, in order:

1. Next.js dev server on `:3000` (defensive — usually already gone via
Ctrl-C)
2. docker compose stack (project `banking-memory`), **containers only**
by default so a re-run of `run-demo.sh` reuses the built composite image
+ seeded Postgres
3. native Metal TEI on `:7067` (Apple Silicon; the host process docker
doesn't manage) — SIGTERM, then SIGKILL for anything that ignores it

## Flags

- `--purge` — also delete the docker volumes (postgres/redis/minio/tei
model cache) for a full clean-slate reset
- `--keep-tei` — leave the slow-to-warm native embedder running when
only bouncing the stack

## Testing

- `bash -n stop-demo.sh` — syntax clean
- `shellcheck stop-demo.sh` — clean, no warnings
- `./stop-demo.sh --help` renders the banner correctly

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-08 09:53:44 -07:00
Ben Taylor 04461409e5 fix(bot): move runStateStoreConformance to @copilotkit/bot/testing subpath (#5875)
## Problem

`@copilotkit/bot`'s package entry re-exports `runStateStoreConformance`
from `./testing/state-store-conformance`, which does `import { describe,
it, expect, ... } from "vitest"` at module top-level. In ESM a static
re-export **eagerly evaluates** the re-exported module, so a plain:

```ts
import { createBot } from "@copilotkit/bot";
```

drags `vitest` into the consumer's runtime module graph and throws
`ERR_MODULE_NOT_FOUND: Cannot find package 'vitest'` for any consumer
that doesn't have vitest installed (i.e. every production consumer).
`vitest` is only a devDependency.

Surfaced while smoke-testing the package rename (OSS-438) — but it's a
pre-existing bug on `main`, independent of that rename.

## Fix

- **Drop the re-export from `src/index.ts`** → the package entry is now
vitest-free.
- **Publish the helper under a `./testing` subpath**
(`@copilotkit/bot/testing`) — test tooling lives off the runtime entry,
the standard pattern.
- **Declare `vitest` as an optional `peerDependency`** so consumers of
`/testing` get the right signal.
- **Docs** updated to `import { runStateStoreConformance } from
"@copilotkit/bot/testing"`.

Only the import path of the test-only conformance helper changes; the
runtime API is untouched.

## Verification
- Static import trace: the entry graph is 12 runtime modules, **none**
import vitest; every vitest importer is a `.test.js` (not in the graph)
or `testing/state-store-conformance.js` (only reachable via `/testing`).
- `@copilotkit/bot` builds; **143/143** tests pass; `publint` + `attw`
clean (the internal conformance test imports the helper by relative
path, unaffected).

## Coordination
Touches `packages/bot` on `main`. The OSS-438 rename PR (#5849) renames
this package to `@copilotkit/channels`; that PR re-derives from `main`
before merge, so it will absorb this fix automatically. If #5849 merges
first, this rebases onto `packages/channels` mechanically.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-08 11:52:49 -05:00
Maxim 95430de51a chore(banking): add stop-demo.sh teardown companion to run-demo.sh
run-demo.sh detaches everything except the Next.js dev server (docker
compose up -d, native Metal TEI via nohup/disown, then exec pnpm dev), so
Ctrl-C on the dev server leaves the docker stack and the host embedder
running. stop-demo.sh brings those leftovers down in one command.

Tears down, idempotently:
  - the Next.js dev server on :3000 (defensive; usually gone via Ctrl-C)
  - the docker compose stack (project banking-memory), containers only by
    default so a re-run reuses the built image + seeded data
  - the native Metal TEI on :7067 (Apple Silicon; the host process docker
    doesn't manage), SIGTERM then SIGKILL

Flags: --purge also drops volumes for a clean slate; --keep-tei leaves the
slow-to-warm embedder running when only bouncing the stack.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 18:49:34 +02:00
Benjamin Taylor 224587101f fix(bot): move runStateStoreConformance to @copilotkit/bot/testing subpath
The package entry (@copilotkit/bot) re-exported runStateStoreConformance from
./testing/state-store-conformance, which imports vitest at module top-level.
An ESM re-export eagerly evaluates that module, so a bare
`import { createBot } from "@copilotkit/bot"` dragged vitest into every
consumer's runtime graph and threw ERR_MODULE_NOT_FOUND when vitest wasn't
installed (i.e. any production consumer).

- Drop the re-export from src/index.ts (entry is now vitest-free)
- Publish the conformance helper under the ./testing export subpath
- Declare vitest as an optional peerDependency (documents the /testing need)
- Update docs to import from @copilotkit/bot/testing

Names/behavior of the runtime API are unchanged; only the import path for the
test-only conformance helper moves.
2026-07-08 11:44:01 -05:00
Mike Ryan 25339b0d07 chore: release monorepo v1.62.3 (#5876)
## Release monorepo v1.62.3

**Scope:** `monorepo` | **Bump:** `patch`

---

### How this release process works

1. **This PR was created automatically** by the "release / create-pr"
workflow.
   It bumped the `monorepo` packages to `1.62.3`
   and generated AI-enhanced release notes.

2. **CI runs on this PR** — the full test suite (unit tests, lint, type
checks, build)
   must pass before merging. This is the review gate.

3. **Review the release notes** in `release-notes.md` in this PR.
If a Notion draft was created, you can edit the release notes there
before merging.

4. **When this PR is merged**, the `release / publish` workflow
automatically:
   - Builds all packages
   - Publishes the `monorepo` packages to npm at version `1.62.3`
   - Creates git tag `monorepo/v1.62.3`
   - Creates a GitHub Release with the final release notes

### Before merging

- [ ] CI is green (tests, lint, types, build)
- [ ] Version bumps look correct
- [ ] Release notes are accurate (edit in Notion if a draft was created)

---

> **Do not merge until CI is fully green.** The full test suite runs
automatically on this PR.
v1.62.3
2026-07-08 09:35:28 -07:00
Jordan Ritter ed44611263 fix(showcase): capture wait -n exit code under set -e so restart diagnostics aren't dead code
Both entrypoints run under set -e. The tail `wait -n $AGENT_PID $NEXTJS_PID`
returns non-zero on the PRIMARY designed exit path (137 = size-gate/watchdog
SIGKILL of the agent tree, or an agent crash), so set -e aborted the script AT
that line — making EXIT_CODE=$?, the entire 'which process exited with code N'
diagnostic, and the final `exit $EXIT_CODE` dead code on exactly the
interesting exits. Capture the code with `EXIT_CODE=0; wait -n ... || EXIT_CODE=$?`
so the diagnostic and explicit exit run and preserve the exact code (incl. 137);
the container-restart path is unchanged.

Same class: langgraph's LANGGRAPH_SIZE_THRESHOLD_MB was used in
`[ "$DIR_SIZE_MB" -ge "$threshold" ]` with no numericity guard, so a
non-integer operator override made the test error and silently no-op the size
gate every cycle. Validate the threshold the same way DIR_SIZE_MB already is
(numeric case guard + 'size guard inactive' WARNING, then skip safely).
2026-07-08 09:25:04 -07:00
tylerslaton 4394f9c81d chore: release monorepo v1.62.3 2026-07-08 16:17:36 +00:00
Alem Tuzlak 2330dca267 fix(bot-slack,runtime): align tests with renderer status + AbstractAgent.run
Two pre-existing test failures on this branch, surfaced by CI's unit +
check-types jobs once main was merged:

- bot-slack event-renderer: the non-pane thread tool-call test still
  asserted the old "no composer status" behavior. Commit 13248dda0b
  deliberately drove setStatus on ANY thread anchor (not just panes), so
  the test now expects both the 🔧 row and the "is using…" status.
- runtime in-memory-runner: HangingAgent/AbortableAgent extended
  AbstractAgent but omitted the abstract run() member (@ag-ui/client
  0.0.57), failing tsc on the test tsconfig (TS2515). Add the same
  run() => EMPTY stub the sibling test agents use.
2026-07-08 18:15:29 +02:00
Jordan Ritter 5c5e139484 fix(showcase/strands-typescript): add startup-grace window to health watchdog for parity with langgraph
The health-watchdog armed its 3-strike/~90s kill counter immediately with no
startup-grace window. langgraph-typescript has a 180s grace precisely to keep a
slow cold start from being killed mid-boot into a restart loop. Now that the
tree-kill makes the strands kill effective (the orphan bug previously made it
cosmetic), a slow tsx cold start (>90s) would be genuinely killed and loop.

Port langgraph's grace mechanism verbatim (GRACE=180, no env override, poll
every 5s, exit 0 on agent death during startup, arm anyway if grace elapses),
adapted to strands' :8000/health probe.
2026-07-08 09:13:48 -07:00
Jordan Ritter 31a9d072e8 fix(showcase/langgraph-typescript): harden size-watchdog against non-numeric du and transient errors
Two tightly-related defects in the size-gated restart machinery in
entrypoint.sh:

1. _watchdog_check_size_once validated the du/awk result only for
   emptiness, not numericity. A non-integer value (junk du output, a
   transient read error, a test-seam stub) reached the
   `[ "$DIR_SIZE_MB" -ge ... ]` comparison and threw "integer expression
   expected"; sitting inside an `if`, set -e was suppressed so the test
   evaluated false and the size gate was SILENTLY skipped with no
   warning (unlike the empty-string branch). Now match ^[0-9]+$ via a
   case and emit the same "size guard inactive" WARNING, so the gate can
   never silently disappear.

2. The size sub-loop used `_watchdog_check_size_once || break`, treating
   ANY non-zero (including a transient check error) as a kill and
   permanently ending the monitor for the container's lifetime. Now
   break ONLY on the real-kill signal (rc==1) — preserving the
   kill -> wait -n -> container-restart -> boot-purge contract — while a
   transient non-zero keeps the monitor live and re-checks next cycle.

Verified RED->GREEN against the real entrypoint in node:22-slim with a
stubbed du seam: non-numeric du now warns and keeps the gate active; a
transient error no longer permanently disables the loop.
2026-07-08 09:13:43 -07:00
Jordan Ritter 31a4377853 fix(showcase): bounded re-scan in _kill_agent_tree so mid-walk forks can't escape
The tree-kill enumerated agent descendants in a single /proc snapshot then
killed. A child that forks a new child (or reparents) between the scan and the
kill escaped the walk, reparented to PID 1, and kept the agent port bound —
defeating the tree-kill's whole purpose of freeing the port before the
container restart.

Replace the single snapshot with a BOUNDED re-scan loop: keep the root alive as
the walk anchor, re-enumerate and SIGKILL live descendants deepest-first each
pass (up to 5 passes, 0.2s apart) until a scan comes back empty, then kill the
root last. Killing the root FIRST would immediately reparent every descendant to
PID 1 and make them unreachable by the root-anchored PPID walk, so root-last is
required for the re-scan to reap late/mid-walk descendants. A descendant that
fully daemonizes (double-fork to PID 1) before we reach it remains out of reach
— documented as an inherent limit of PPID-based reaping without job control; the
agent's npm->node tree does not daemonize.

Also document why the ${stat##*) } PPID parse is safe against a comm containing
") " (longest-prefix to the last ") " always lands on the true terminator).

Applied identically to langgraph-typescript (:8123) and strands-typescript
(:8000). Proven via local RED-GREEN in node:22-slim: pre-fix leaks a mid-walk
escapee (port stays bound), post-fix reaps it (0 orphans, port freed).
2026-07-08 09:13:38 -07:00
Jordan Ritter a5f082f50c fix(showcase): tree-kill agent in cleanup() EXIT trap to prevent shutdown orphan
The cleanup() EXIT/SIGTERM trap in both langgraph-typescript and
strands-typescript entrypoints did a bare `kill $AGENT_PID`. Because
$AGENT_PID is the outer process-substitution subshell (not the real
npm->node server), this reaped only the subshell and orphaned the node
server (reparented to PID 1, still holding :8123 / :8000) on every
graceful/SIGTERM shutdown -- e.g. every Railway redeploy/rollover.

Route cleanup() through the existing _kill_agent_tree helper (as the
size-watchdog and health-strike kill sites already do), and move the
_agent_descendants/_kill_agent_tree helpers above cleanup()/the trap so
they are defined whenever the trap can first fire.
2026-07-08 09:11:29 -07:00
Sam Julien 39a86447db docs(shell-docs): update Slack and Teams agent messaging 2026-07-08 09:04:47 -07:00
Benjamin Taylor 71a4ac42e4 Merge origin/main into alem/oss-360-sdk-foundations
Brings the 499-commit-stale foundations branch up to date with main so #5761
has a clean diff and no stale reverts (e.g. forwardHeaders). Conflicts:
- CopilotThreadsDrawer.tsx: took main's (main renamed CopilotDrawer -> ThreadsDrawer
  + added the collapse feature; the branch's edit was a no-op import-type split).
- pnpm-lock.yaml: regenerated with the pinned pnpm 10.33.4 (adds @copilotkit/bot-intelligence).
2026-07-08 11:01:58 -05:00
Jordan Ritter 93f2abeeb5 fix(showcase/strands-typescript): tree-kill agent so health-strike restart actually fires
strands-typescript/entrypoint.sh carries the identical latent trap fixed in
langgraph-typescript by this branch. The agent is launched through a process
substitution — `cd /app/src/agent && npm start &> >(awk …) &` — so
$AGENT_PID (=$!) is the outer subshell wrapping that pipeline, NOT the npm→node
tree it forks (`npm start` runs `node --import tsx server.ts`, which stays a
child of npm, not an exec-replacement). The health-strike `kill -9 $AGENT_PID`
therefore reaps only the subshell; npm and node reparent to PID 1 and KEEP
RUNNING, still bound to :8000. `wait -n` never observes the real server die →
container never restarts → the frontend proxies to a dead-but-not-restarted
agent forever (edge 502s). strands-typescript has no size-gate, so this only
fires after the 3-strike (~90s) health counter exhausts, but it is a real
latent footgun with the same root cause.

Fix: reuse the /proc-based `_kill_agent_tree` helper (node:22-slim ships
neither ps nor pgrep, and job control is off so a group kill would take out
the whole entrypoint) at the single health-strike kill site. The whole
npm→node tree now dies, :8000 is freed, `wait -n` returns and the container
restarts.

Red-green proven in a real node:22-slim container against the exact
process-sub → npm → node structure: RED (bare kill -9 $AGENT_PID) leaves node
orphaned and :8000 still LISTENing; GREEN (_kill_agent_tree) reaps the tree,
0 orphans, port freed.
2026-07-08 08:51:15 -07:00
Jordan Ritter e9284090c1 fix(showcase/langgraph-typescript): tree-kill agent so size-watchdog restart actually fires
The size-gated watchdog added in ef103f5f5 does `kill -9 $AGENT_PID`
expecting the container to exit and Railway to restart (re-running the
boot-purge). But $AGENT_PID is the process-substitution subshell wrapping
`cd /app/src/agent && npm start &> >(awk …)`, NOT the npm→node tree it
forks. A single-PID kill reaps only that subshell; npm and node reparent
to PID 1 and keep running, still bound to :8123 with the bloated in-memory
state resident. The frontend then proxies to a dead-but-not-restarted
agent and the edge 502s forever.

Fix: add a /proc-based `_kill_agent_tree` (node:22-slim ships neither ps
nor pgrep, and job control is off so a group kill would take out the whole
entrypoint) and use it at both watchdog kill sites (size gate + health
strikes). The whole npm→node tree now dies, :8123 is freed, `wait -n`
returns, the container restarts and re-runs boot-purge — preserving the
original RangeError-prevention intent.
2026-07-08 08:46:57 -07:00
Ben Taylor e283629046 docs: CopilotThreadsDrawer guide + Threads updates + React reference (closes ENT-1021) (#5780)
Documents the new **CopilotDrawer** prebuilt threads drawer (component
PR #5746).

## Changes
- **Guide** — `docs/prebuilt-components/copilot-drawer.mdx` (new) +
registered in `prebuilt-components/meta.json`. React drop-in
(`<CopilotDrawer />` beside `<CopilotChat />`, zero active-thread
wiring), props table, customization (slots / `::part`s /
`--cpk-drawer-*` tokens), Angular usage, license.
- **Threads how-to** — `snippets/shared/threads/threads.mdx` (shared →
propagates to ~10 integration threads pages + `/threads`): a callout
recommending `CopilotDrawer` as the prebuilt path and framing the
`useThreads` steps as the **headless** alternative (kept, not removed) +
Next-steps cross-links.
- **Reference** — `reference/components/CopilotDrawer.mdx` (React) and
`reference/angular/components/CopilotDrawer.mdx` (Angular),
hand-authored with `<PropertyReference>`.

## Validation
`npm run build` in `showcase/shell-docs` is green locally — compiled
successfully, 215/215 static pages generated, no MDX errors. All
internal links verified to resolve on `main`.

## Why draft / release-gated
Merges **with or after** the drawer release
(`@copilotkit/web-components` published +
`react-core`/`@copilotkit/angular` > 1.61.2 containing `CopilotDrawer`).
Until then the documented imports don't exist in a published package.

## Follow-ups (out of scope)
- Live `<InlineDemo>` of the drawer (needs a demo-registry entry) — uses
plain code blocks for now.
- Angular `injectThreads` / `CopilotChatConfiguration` reference pages
(named without links here; they don't exist on `main` yet).

Spec: https://app.notion.com/p/38f3aa381852814e8884e3153d3d4688 ·
Tracking: ENT-1021

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-08 10:43:42 -05:00
Alem Tuzlak d541d900f4 feat(bot): SDK realtime render-event streaming + Bolt-free Slack renderer (OSS-402 / OSS-403) (#5786)
Stacked on #5761 (base: `alem/oss-360-sdk-foundations`). The SDK side of
the Hosted Bots **realtime** path, per the source-of-truth Notion plan
and the OSS-395 frozen contract.

## What this delivers

### OSS-403 — extract a Bolt-free Slack renderer
(`@copilotkit/bot-slack/render`)
`createRunRenderer` no longer takes a `WebClient`; it takes an injected
`SlackRenderTransport` (the 3 credentialed ops it actually calls —
`setStatus` / `postMessage` / `updateMessage`; the 4 native streaming
ops were already injected via `NativeStreamTransport`). New `./render`
subpath export exposes the transport-agnostic renderer plus the
already-pure IR→Block Kit / modal / mrkdwn helpers, so the gateway-side
**Connector Outbox (OSS-404)** can drive the *identical* renderer for
managed replies — 1:1 UX parity without forking. The native Slack
adapter wraps its own `WebClient` into the transport.
- **Zero behavior change** to the native bot — 272 `bot-slack` tests
pass, check-types green.

### OSS-402 — stream RenderEvents over the realtime gateway
The managed adapter (`@copilotkit/bot-intelligence`) now mints semantic
render frames (`run_started` / `text_delta` / `text_end` / `tool_start`
/ `tool_end` / `interrupt` / `run_error` / `finalize`) and streams them
through a new `RenderEventSink`, assigning a monotonic `seq` per
`(turnId, slot)` and awaiting a durable `render_accepted` receipt for
each. Ordering is guaranteed by a serial chain with `seq` fixed at
enqueue time (so it holds regardless of AG-UI callback scheduling); a
rejected push surfaces at drain and nacks the delivery.

`PhoenixRealtimeTransport` (implements `DeliverySource` +
`RenderEventSink`) speaks the frozen OSS-395 contract exactly:
`render_event` frames → `render_accepted` receipts, then
`delivery.complete_requested` (completion **intent**, carrying
`acceptedThrough` high-water pointers) — **never** a committed
`delivery.ack` (app-api owns ack), and **no Slack credentials** in the
SDK. The Phoenix `Socket`/`Channel` boilerplate is expressed against a
minimal injected `HostedBotChannel` so the protocol is fully unit-tested
with a fake channel.

When no realtime sink is wired, the renderer falls back to translating
frames into `post` ops on the `EgressSink`, so the existing HTTP demo
keeps posting plain-text replies.

## Tests
- `@copilotkit/bot-slack`: 272 pass (native renderer behavior preserved
through the transport swap).
- `@copilotkit/bot-intelligence`: 43 pass (37 baseline + 6 new) — frame
ordering + `turnId:slot:seq`, completion-after-receipt, and the
**never-self-ack** invariant.
- `@copilotkit/runtime` check-types green (fixes the pre-existing
`get-runtime-info` `bots` red flagged on #5761).

## Follow-ups (not in this PR)
- **Gateway `complete_requested` handler (Intelligence #466):**
`sdk_channel.ex` currently routes `render_event` / `ack` / `fail` but
not `complete_requested`; it needs a `handle_in` clause +
`app_api_client.complete_delivery` + a matching app-api completion
route. Coordinating with @TylerSlaton since it's his file / shared
branch (no local Elixir toolchain to verify here).
- **OSS-404 Connector Outbox** consumes `@copilotkit/bot-slack/render`
to render frames → real Slack messages; end-to-end realtime parity isn't
demoable until it lands.
- Discrete `EgressSink` posts (command/interaction replies) →
`post`/`update` render frames (needs a per-`(turn, slot)` seq shared
with the run renderer).
2026-07-08 17:15:16 +02:00
Ben Taylor 2b5f856692 feat(suggestions): stateless suggestion generation via /suggest (ENT-1018) (#5799)
> **Update (SSE rework — addresses review):** `/suggest` now **streams
AG-UI SSE** instead of buffering a JSON `{ messages }` response, and the
run **forwards the consumer's messages + state**. Server-side it reuses
`createSseEventResponse` (the runner's event pipeline minus
`GLOBAL_STORE` persistence, `captureTelemetry:false`); client-side it
drives a stock `HttpAgent` at `/agent/:id/suggest`, so chips fill in
progressively via `onMessagesChanged` and the run never touches the
Intelligence websocket delegate. The stateless and fallback paths now
share one `runAgent` flow (net −68 LOC of production code). The `## How`
/ behavioral notes below are updated to match.

## What & why

Dynamic suggestions were implemented as a **full shadow-thread agent
run** (`SuggestionEngine.generateSuggestions` clones the provider agent
onto a throwaway `threadId` and calls `runAgent`). Against a
thread-persisting backend (CopilotKit Intelligence) every reload
materialized a **listed, auto-named thread** (plus gateway events + a
run lock), flooding the thread drawer. Root cause is the design: a
suggestion is a **stateless structured completion**, not a persisted
conversation.

This makes it one. A suggestion now runs the provider agent **directly**
behind a dedicated `POST /agent/:agentId/suggest` handler — no thread,
lock, gateway, runner-store, or name-gen — for **all**
CopilotKit-runtime backends. The debris is structurally impossible
rather than hidden.

## How

- **`get-runtime-info`** advertises a `suggestions` capability on `GET
/info` (`RuntimeInfo.suggestions`).
- **`handleSuggestAgent`** (new) runs the resolved provider agent
directly and **streams its AG-UI events as SSE** via
`createSseEventResponse` — the runner's event pipeline
(`agent.runAgent({ onEvent })` + `finalizeRunEvents`) **minus** the
`GLOBAL_STORE` persistence that backs SSE-mode thread listings.
`captureTelemetry:false` and no debug bus keep suggestions out of run
telemetry/the inspector. Header-forwarding only; no middleware.
- **Router**: `POST /agent/:agentId/suggest` wired through
`fetch-router`/`fetch-handler` (multi- and single-route), with
`assertNever` exhaustiveness guards.
- **core `SuggestionEngine`**: when the runtime advertises `suggestions`
(and transport isn't single-route), it seeds a stock `HttpAgent`
(pointed at `/agent/:id/suggest`, credentials via a fetch wrapper) with
the consumer's deep-cloned messages + state and `runAgent`s it — a plain
`HttpAgent` only speaks REST SSE, so it never routes through the
Intelligence websocket delegate. Otherwise it falls back to the
clone+`runAgent` path. Both paths share one flow; abort-aware; failures
logged.

## Testing

Unit + integration across both packages (**504 core + 1587 runtime
green**, `check-types` clean): the **no-thread-leak** proof (real
`InMemoryAgentRunner`, asserts the suggest thread never appears in the
live listing), progressive-streaming + state-forwarding assertions,
cross-mode SSE handler behavior, error/abort robustness (Safari
`DOMException` + undici non-`AbortError`), header/credential forwarding,
multi-route `200` + `GET→405`, and single-route/`suggestions:false`
fallback.

Validated end-to-end against a running runtime + real `CopilotKitCore`
client over HTTP (local built packages):
- **In-memory managed threads:** a normal `/run` creates exactly 1
listed thread; **4 dynamic-suggestion reloads add 0**. Chips stream
progressively (`onSuggestionsChanged` 0→1→2); the `/suggest` request
carries the consumer's state.
- **Live hosted CopilotKit Intelligence** (`mode: "intelligence"`, real
gateway): `/info` advertises the capability, suggestions stream via the
stateless path, and the **hosted thread listing is byte-identical
(50→50) after 6 reloads** — the drawer's actual data source is
untouched.

## Compatibility

**Migrations:** none. No schema/DB change; self-hosted deployments need
no coordinated update — the change is entirely in `@copilotkit/core` +
`@copilotkit/runtime`. No release flag.

**Additive + capability-gated — version skew is safe both directions:**
- **New core + old runtime** (no `/suggest`, capability absent):
`core.suggestions` is `undefined` → client uses today's clone+`runAgent`
path.
- **Old core + new runtime**: the new optional `RuntimeInfo.suggestions`
field is ignored; the `/suggest` endpoint sits unused.
- **New + new**: stateless `/suggest`.

`RuntimeInfo.suggestions` is a new **optional** field and the
`/agent/:agentId/suggest` route (+ `RouteInfo`/`METHOD_NAMES` entries)
are purely additive. No exported symbol was removed or renamed.

**Behavioral notes (matched new versions):**
- Dynamic suggestions **stream progressively** over SSE (chips fill in
as the provider emits them), matching the pre-`/suggest` UX.
- Suggestion runs no longer flow through the run handler, so they create
**no thread** (the fix) and won't appear in `oss.runtime.*` run
telemetry.
- Single-route transport and non-CopilotKit AG-UI backends keep the
clone+`runAgent` fallback.

**⚠️ Deploy note:** a reverse proxy that path-allowlists CopilotKit
routes must add `POST /agent/:agentId/suggest`. If the capability is
advertised but that path is blocked, suggestions silently no-op — the
client does **not** fall back on a `/suggest` error (by design, to avoid
re-introducing the thread flood).

## Review

Landed through a full CR loop (3 rounds / 21 agent-reviews + a
bucket-(c) promotion audit) — bucket (a) converged to zero. Known
pre-existing follow-ups tracked separately (out of scope):
`resolveLicenseStatus` grace-period ordering and
`AgentRegistry.getAgent` using `in` vs `hasOwnProperty` for reserved
ids.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-08 08:47:31 -05:00
Alem Tuzlak 7e74416951 feat(bot-teams): add ./render export for managed reuse 2026-07-08 13:48:25 +02:00
QA Agent 2b0983b1fa docs: add zodState and proper node context to Deep Agents state rendering
- Add zodState import and wrapper in TypeScript state schema example
- Show state emission as chatNode function with proper signature
- Align Deep Agents pattern with LangGraph state rendering docs
- Fixes FAC-63: ensures custom state properties appear in STATE_SNAPSHOT events
2026-07-07 18:53:45 -07:00
QA Agent 5ccb64b679 docs(deep-agents): add missing zodState wrapper in shared-state TypeScript examples
- Add zodState import to in-app-agent-read.mdx and in-app-agent-write.mdx
- Wrap language field with zodState() to ensure it appears in AG-UI and useAgent state
- Matches pattern used in predictive-state-updates.mdx

Fixes: FAC-48
2026-07-07 18:12:36 -07:00
QA Agent 2249efa114 docs(showcase): fix Python state streaming examples in Deep Agents and LangGraph docs
- Replace self.state with state in manual predictive state updates example
- Add missing colon in step_progress_tool function definition
- Align Python examples with working code patterns from examples/v1/travel/agent

Fixes FAC-53
2026-07-07 17:50:53 -07:00
QA Agent 42f611794c docs(deepagents): add complete custom graph example with StateGraph setup
- Replace createMiddleware pattern with Annotation.Root for custom graphs
- Add complete chatNode function showing copilotkitEmitState usage
- Include full StateGraph setup: creation, node addition, edges, compilation
- Add explanatory callout distinguishing custom graphs from prebuilt agents
- Resolves FAC-52
2026-07-07 17:17:32 -07:00
Benjamin Taylor 3efa375afb docs(drawer): re-capture preview with the real default components (#5780 review)
The prior preview paired the real <copilotkit-threads-drawer> with a hand-coded
mock chat panel (from the screenshot harness), so the chat half wasn't an actual
CopilotKit component — which is what the reviewer flagged. Re-captured with the
real default <CopilotThreadsDrawer> + <CopilotChat> together, stock (untheme d)
light styling, showing a thread's replayed conversation.
2026-07-07 17:54:26 -05:00
Benjamin Taylor 5994bfe482 Merge origin/main into ben1/ent-1018-stateless-suggestions
Syncs the branch with main (304 commits) to resolve CI type-check failure.
main changed extractForwardableHeaders to require a forwarding policy and
added the mergeForwardableHeaders helper (#5712); handle-suggest now uses
mergeForwardableHeaders(agent.headers, request, runtime.forwardHeadersPolicy ??
resolveForwardHeadersPolicy(undefined)) to match the run handler — fixing the
drift and adopting the server-headers-win / infra-header denylist behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 17:40:50 -05:00
Benjamin Taylor 9f938e89cf refactor(suggestions): stream stateless /suggest over SSE and forward consumer state
Rework the stateless /suggest transport to reuse the AG-UI SSE pipeline
instead of a buffered JSON response, resolving the streaming + state review
feedback:

- server runs the provider agent directly and streams its events via
  createSseEventResponse (the runner's event pipeline minus GLOBAL_STORE
  persistence), gated with captureTelemetry:false so suggestions stay out of
  run telemetry
- client drives a stock HttpAgent against /agent/:id/suggest, so chips stream
  progressively via onMessagesChanged and the run never routes through the
  Intelligence websocket delegate (still no thread persistence)
- forward the consumer's deep-cloned messages + state onto the suggestion run
  (was state: {}), matching the clone fallback

Net -68 LOC of production code; the stateless and fallback paths now share one
runAgent flow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 17:24:46 -05:00
Benjamin Taylor af10862e12 docs(threads): retitle /threads to 'Headless Threads' + surface CopilotThreadsDrawer on prebuilt pages (#5780 review)
- /threads page title -> 'Headless Threads' to distinguish the headless
  useThreads path from the prebuilt drawer (slug kept, so no inbound links
  break; sidebar label follows the frontmatter title). (samjulien #9)
- prebuilt-components index: the 'saved conversations' line now leads with the
  drop-in CopilotThreadsDrawer and offers Headless Threads as the DIY path, plus
  a companion-sidebar mention in 'Pick a surface' — the drawer was absent from
  the prebuilt landing page.
- chat page: same, point at the prebuilt drawer first, headless second.
2026-07-07 17:04:28 -05:00
Benjamin Taylor 3c174edcfd docs(drawer): rename is headless-only, complete the CSS parts list, clarify the zero-wiring line (#5780 review)
- Remove 'rename' from the prebuilt CopilotThreadsDrawer capability claims
  (guide, React reference, shared Threads callout) — the row kebab only does
  archive/unarchive + delete. Add an explicit note that rename is available via
  the headless useThreads path. (MikeRyanDev)
- Reference CSS parts list now matches the shipped element: adds row/row-active,
  collapse-toggle, close-toggle, backdrop, launcher-cluster, launcher-new-thread,
  load-more, fetching-more, fetch-more-error, fetch-more-retry, licensed,
  licensed-cta; grouped by area. (MikeRyanDev)
- Rewrite the 'no threadId state / no onSelect plumbing' line to stand on its own
  by contrasting with a hand-rolled sidebar. (samjulien)
2026-07-07 17:04:27 -05:00
Benjamin Taylor f4ec551809 docs(drawer): wrap drawer + chat in a shared CopilotChatConfigurationProvider so selection drives the chat [ENT-1051] 2026-07-07 17:04:27 -05:00
Benjamin Taylor e95cc3a5ca docs(drawer): document restored collapsible + onCollapseChange; fix stale 'no collapse control' prose [ENT-1051] 2026-07-07 17:04:27 -05:00
Benjamin Taylor 68c9ac84fc docs(drawer): refresh preview screenshot to show the desktop collapse control [ENT-1051] 2026-07-07 17:04:27 -05:00
Benjamin Taylor 0929ba16fa docs(drawer): refresh preview with aligned New Conversation row [ENT-1051]
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 17:04:27 -05:00
Benjamin Taylor c321a65854 docs(drawer): refresh preview (persistent sidebar, no search/collapse chrome) [ENT-1051]
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 17:04:27 -05:00
Benjamin Taylor 10861da99d docs(drawer): remove collapse API; persistent sidebar on desktop, off-canvas on mobile [ENT-1051]
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 17:04:26 -05:00
Benjamin Taylor 4c101a3cd0 docs(drawer): refresh preview screenshot (search removed) [ENT-1051]
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 17:04:26 -05:00
Benjamin Taylor df74bcebd5 docs(drawer): remove search; document collapsible + collapse-change [ENT-1051]
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 17:04:26 -05:00
Benjamin Taylor b3d473226f docs(drawer): update CopilotThreadsDrawer reference/guide for the UX redesign [ENT-1051]
New parts, recentLabel, and search; header/kebab/funnel changes.
2026-07-07 17:04:26 -05:00
Benjamin Taylor 9137887352 docs(drawer): refresh CopilotThreadsDrawer preview for the UX redesign [ENT-1051]
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 17:04:26 -05:00
Benjamin Taylor 3532370de9 docs(drawer): add CopilotThreadsDrawer preview screenshot
Stand-in for a live showcase example (out of scope for this PR): a real
screenshot of <CopilotThreadsDrawer> beside <CopilotChat>, rendered from the
v2 react demo against the Intelligence platform. Embedded as a <Frame> preview
right under the intro.
2026-07-07 17:04:26 -05:00
Benjamin Taylor 808e0256a1 docs(drawer): rename CopilotDrawer -> CopilotThreadsDrawer
Match the final component name. Renames the guide and reference pages
(copilot-drawer.mdx -> copilot-threads-drawer.mdx, CopilotDrawer.mdx ->
CopilotThreadsDrawer.mdx), their slugs/URLs, the nav meta entry, the
data-testid default, the <copilotkit-threads-drawer> element mention, and
all prose/import references. The --cpk-drawer-* CSS tokens and ::part names
are unchanged.
2026-07-07 17:04:25 -05:00
Benjamin Taylor 799be82723 docs(drawer): desurface the license-gate API; one neutral locked-view line
Per review: remove the onUnlicensed prop, the unlicensed slot, and the
unlicensed/unlicensed-cta parts from the guide + reference so neither
humans nor agents surface them. Replace with a single neutral line:
threads require Intelligence; a locked view shows without a license key.
2026-07-07 17:04:25 -05:00
Benjamin Taylor 29e4f66d44 docs(drawer): rename upsell -> unlicensed (match the renamed API) 2026-07-07 17:04:25 -05:00
Benjamin Taylor 31ab23ddc5 docs(drawer): sign-up CTA + guide rewording; threads pages for 4 frameworks
- Guide: lead with the user benefit (less reference-y opening), reframe the
  headless useThreads alternative to stand alone, add the OpsPlatformCTA
  sign-up callout (per review).
- Add threads.mdx (shared-snippet include) for a2a, adk, agent-spec,
  deepagents + register each under Intelligence Platform in meta.json.
2026-07-07 17:04:25 -05:00
Benjamin Taylor 5fb4802b88 docs(drawer): remove Angular content for now (React-only)
Per review: defer the Angular drawer docs. Removes the Angular reference
page, the guide's Angular section, and Angular cross-links; keeps the
React guide + reference + the Threads how-to callout.
2026-07-07 17:04:25 -05:00
Benjamin Taylor 6ec4124323 docs(drawer): document the limit prop (thread pagination / Load more) 2026-07-07 17:04:25 -05:00
Benjamin Taylor 25ded0d7c2 docs: add CopilotDrawer guide, reference (React + Angular), and Threads updates
- New prebuilt-components guide (docs/prebuilt-components/copilot-drawer.mdx)
  + nav registration; React drop-in, customization, Angular usage.
- New React + Angular reference pages.
- Threads how-to (shared snippet): recommend CopilotDrawer as the prebuilt
  path, frame useThreads as the headless alternative, cross-link.

Release-gated: merges with/after the drawer ships (ENT-1021).
2026-07-07 17:04:24 -05:00
Ben Taylor b24c3e4135 feat(web-components,react,vue,angular): CopilotThreadsDrawer UX redesign (ENT-1051) (#5823)
Redesigns the shared `<copilotkit-threads-drawer>` element
(`@copilotkit/web-components`) to the new Figma UX, keeping the React,
Vue, and Angular wrappers in lockstep. Pure-VIEW change — no
`@copilotkit/core`, runtime, or `useThreads` changes.

**Ticket:** [ENT-1051](https://linear.app/copilotkit/issue/ENT-1051) ·
**Figma:** [Thread
Drawer](https://www.figma.com/design/feSsBJw1qCfLp0JNnOurrJ/CopilotKit-Intelligence?node-id=723-78)
· **Spec:**
[Notion](https://app.notion.com/p/3953aa381852819ab464dae3894e7f18)

## What changed
- **Header** → right-aligned icon row. On desktop it holds the
**collapse** toggle (sidebar glyph); on mobile the **close** toggle. No
title text, no "+ New" pill. Optional `slot="header"` preserved (empty
by default; the toggle right-aligns after it).
- **New Conversation** row (plus-square + label) below the header —
keeps `part="new-thread-button"` + the `new-thread` event.
- **Recent Conversations** heading + **funnel** filter icon → Active/All
popover. Preserves `_filter` + `filter-change` and
`part="filter-active"`/`filter-all"`.
- **Per-row kebab menu** (⋮) holding Archive/Unarchive + Delete —
preserves those events + parts. An open kebab now shields the rest of
the list from hover so it reads as a single surface (see Review fixes).
- **Delete confirm** is a native `<dialog>` opened with `showModal()`
(browser top layer), centered over the drawer's visible box — it can't
paint under other UI or drop below the fold. jsdom falls back to the
`open` attribute.
- **Archived rows** render italic/muted inline in the "All" view.
- **Desktop collapse** → `collapsed` / `collapsible` props (default
**expanded**) + a `collapse-change` event / `CollapseChangeDetail`.
Collapsing sets `--cpk-drawer-reserved-width: 0` on the document root so
the host grid reclaims the column with no hydration flicker.
- **Unified floating cluster** (Figma "closed" mockup) =
`[sidebar-toggle] [+ New Conversation]`, shown in both the mobile-closed
and desktop-collapsed states. Mobile stays an off-canvas modal (backdrop
/ Escape / focus-trap).

## Compatibility
- All existing `::part()` names and events are preserved; only
**additive** parts are introduced: `collapse-toggle`, `close-toggle`,
`section-heading`, `filter-toggle`, `row-menu`, `row-menu-popover`,
`launcher-cluster`, `launcher`, `launcher-new-thread`, plus
`confirm-dialog`/`confirm-cancel`/`confirm-delete`/`backdrop`. One
additive event: `collapse-change`.
- Additive wrapper props: `recentLabel` (all frameworks);
`collapsible`/`collapsed` + `onCollapseChange` (React) / equivalents in
Vue & Angular.
- **Usage note (now in the docs):** the drawer and `<CopilotChat>` must
share a chat-configuration provider so the drawer drives the chat —
`CopilotChatConfigurationProvider` (React/Vue) /
`provideCopilotChatConfiguration()` (Angular). The v2
`CopilotKitProvider` does not provide that context on its own.
- Verified: **no example `::part()` theme changes required** — every
example themes the drawer via inherited `--cpk-drawer-*` custom
properties.

## Descoped / changed during development (re: earlier review)
- **Client-side search was removed at the designer's request.** There is
**no** search UI, `search` event, `search-toggle`/`search-input` part,
or `onSearch` wrapper prop in the shipped element. Any remaining
"search" mention in older comments is stale.
- **Desktop collapse was briefly backed out, then re-restored** per the
designer (commit `8bfd245305`). The shipped element **has** collapse
(`collapsed` is a live public property — it was not removed).

## Review fixes (commit `0b4f6ca392`)
Addressing @MikeRyanDev and @marthakelly:
- **`core/threads.ts`** — a full-list refetch (filter-change / retry)
now clears `fetchMoreError` on both `listRequested` and `listSucceeded`,
so the inline "couldn't load more — retry" banner no longer survives
onto a fresh list.
- **Escape while confirming delete** — the host keydown handler now
consumes Escape while a confirmation is open; previously the bubbled
keydown fell through and closed the whole mobile drawer along with the
confirmation.
- **Open kebab menu shields the list** — `.list.menu-open
.row:not(.menu-open)` gets `pointer-events: none`, so other rows no
longer reveal their kebab / paint a host `::part(row):hover` background
around or behind the open popover. Click-away dismissal is preserved via
the existing document pointerdown handler. (Verified live in the
langgraph-js example.)
- **Docs token** — dropped the removed `--cpk-drawer-rail-width` from
the web-components README.

## Testing
All suites run via `nx`, green through each package's lefthook
pre-commit gate:
- `@copilotkit/web-components` — **92** drawer element tests + `:build`
green. Covers header collapse/close toggles, New Conversation, funnel
filter switch, `recentLabel`, kebab open + archive/delete routing,
confirm-dialog gating + native cancel + **backdrop-click dismiss**,
**Escape-while-confirming (no drawer close)**, **open-menu row shield**,
collapse/cluster/column-reclaim, archived-italic, preserved
parts/events, `header` slot + `label` aria-labels.
- `@copilotkit/core` — **553** tests incl. the new `clears a lingering
fetchMoreError when a full list refetch succeeds`.
- `@copilotkit/react-core` — CopilotThreadsDrawer suite + full package
**1419** green.
- `@copilotkit/vue` — **32** incl. SSR + the `collapsible`
boolean-prop-default regression test.
- `@copilotkit/angular` — CopilotThreadsDrawer spec **35** (incl.
**scoped-chat-input focus**: prefers the ancestor `copilot-chat-view`
over the document-global fallback); full package **178**.

## Follow-on
- Docs (screenshot + reference/guide) on the release-gated docs PR
**#5780**.
- Release (`web-components` + `react-core` + `vue` + `angular`,
lockstep) + CLI scaffolding bump.
- Example grid/theme updates ride the release in **#5828**.
- **[ENT-1080](https://linear.app/copilotkit/issue/ENT-1080)** — dedup
the per-wrapper `findChatInput` / open-state fallback (marthakelly #6,
deliberately deferred as a cross-package refactor).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-07 17:01:00 -05:00
Ben Taylor e297bf9e9e ci(showcase): drop unused runner apt repos before installing bats (#5855)
## Problem

The **Shell script tests (bats + shellcheck)** job in
`showcase_validate.yml` installs `bats` with:

```yaml
sudo apt-get update
sudo apt-get install -y bats
```

GitHub's `ubuntu-latest` runner image preconfigures third-party apt
repos (Microsoft / `azure-cli`, pointing at `packages.microsoft.com`)
for preinstalled tooling. `apt-get update` refreshes **every**
configured repo, not just the ones a job needs. When one of those
Microsoft repos serves invalid release metadata:

```
E: Failed to fetch https://packages.microsoft.com/.../InRelease  Clearsigned file isn't valid, got 'NOSPLIT'
##[error]Process completed with exit code 100.
```

`apt-get update` exits non-zero and — because the step runs under `bash
-e` — the whole step aborts before `bats` installs. This fails the job
even though `bats` comes from Ubuntu's own `universe` repo, which is
unaffected. It's a runner-image / external-repo outage, not anything in
the shell tests.

## Fix

This job only needs Ubuntu packages, so remove the unused third-party
repos before updating:

```yaml
sudo rm -f /etc/apt/sources.list.d/*microsoft* /etc/apt/sources.list.d/*azure-cli*
sudo apt-get update
sudo apt-get install -y bats
```

Ubuntu's archive (where `bats` lives) is in the base `sources.list` and
is untouched, so `bats` still installs; `apt-get update` no longer
refreshes the broken, unused Microsoft repos, so it stops failing the
job.

## Testing

- Change is confined to the `Install bats` step of the
`shell-script-tests` job. The rest of the job (shellcheck + the bats
suite) is unchanged.
- CI on this PR exercises the modified step directly — a green
`shell-script-tests` run here confirms the install path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-07 16:49:39 -05:00