Commit Graph

14241 Commits

Author SHA1 Message Date
Maximiliano Korp 3a46947ffe fix(runtime): wait for joined event channel 2026-08-03 15:58:20 -07:00
Maximiliano Korp 84acddf5b1 feat(runtime): batch durable runner events 2026-08-03 15:58:20 -07:00
Maximiliano Korp 73286b591f fix(runtime): keep accepted runs alive during reconnect 2026-08-03 15:58:20 -07:00
Maximiliano Korp 5cc22a5a1f fix(runtime): preserve gateway handoff continuity 2026-08-03 15:58:19 -07:00
David Sanchez a55e499f1a Port the Pydantic AI example to Pydantic AI v2
`Agent.to_ag_ui()`, `AGUIApp`, and the `pydantic_ai.ag_ui` shim were removed in
Pydantic AI v2, so the example only ran on v1.

- pin `pydantic-ai-slim[ag-ui,openai]>=2.0.0` and `ag-ui-protocol>=0.1.19`
- import `StateDeps` from `pydantic_ai.ui`
- serve via `AGUIAdapter.dispatch_request` on a Starlette route
- give each request its own `deps` copy so state no longer leaks between threads
2026-08-03 17:08:07 -05:00
Sam Julien 5a142af768 feat(skills): add setup-slack-channel and split it from copilotkit-channels (#6340)
## Summary

Brings the `setup-slack-channel` skill into the set that `copilotkit
skills install` distributes, and narrows both it and
`copilotkit-channels` so they stop matching the same request.

## Why

The skill was merged into
[CopilotKit/channels-sdk#7](https://github.com/CopilotKit/channels-sdk/pull/7),
which makes it reachable from a channels-sdk checkout and nowhere else.
`copilotkit skills install` reads `CopilotKit/CopilotKit/skills`, so
until the skill lives here, no CLI user can get it.

No CLI change is needed to pick it up: skill names are free-form
(`--skill` is validated by regex only, with no allowlist) and the
default install is `--skill *`.

## How

**The skill is copied from the merged channels-sdk source**, with one
addition: a `version: 1.0.0` frontmatter field, so it matches the other
standalone skills in this repo (every one of them carries a version;
only the package-mirrored skills omit it). The body, references, and
manifest asset are otherwise unchanged. It stays browser-first and makes
no reference to the `copilotkit channels` commands, per the call to
defer those to the web app until they have more real-world usage.

**Both descriptions are narrowed** so the trigger overlap is gone:

| Skill | Owns | Hands off |
| --- | --- | --- |
| `copilotkit-channels` | The code half — declaring, wiring, and
customising a Channel. Assumes the provider app exists | First-time
Slack setup → `setup-slack-channel` |
| `setup-slack-channel` | The provider half — the Slack app, its tokens,
attaching it to a Channel | Code questions → `copilotkit-channels` |

Before this, both matched "connect my agent to Slack" and the agent
picked whichever it read first. That collision was invisible in
channels-sdk, where `setup-slack-channel` is the only skill present; it
becomes live the moment both ship in the installed set.

## Notes for reviewers

- **Scope is Slack only.** A Teams sibling is deliberately a separate
pass.
- **No existing skill content changes** — the `copilotkit-channels` diff
is its frontmatter description and nothing else.
- Two known follow-ups are tracked and intentionally not addressed here:
[channels-sdk#9](https://github.com/CopilotKit/channels-sdk/issues/9)
(CLI-capability claims, deferred by decision) and
[channels-sdk#2](https://github.com/CopilotKit/channels-sdk/issues/2)
(`build-channels-bot` staleness, unrelated).

Refs CopilotKit/channels-sdk#10

## Added during the `main` merge

Resolving the conflict surfaced a second, unrelated problem that had to
be fixed for this PR to be safe to land.

`skills/setup-slack-channel` is a **standalone** skill — it has no
`packages/*/skills/` source. `scripts/sync-plugin-skills.ts` treats any
such directory as an orphan unless it is listed in
`RESERVED_LIFECYCLE_SLUGS`, which this one was not. Verified against the
pre-fix script:

- `pnpm check:plugin-skills` → exit 1, `orphan file(s) in mirror:
skills/setup-slack-channel`
- `pnpm sync:plugin-skills` (write mode) → **recursively deleted all 8
files of the new skill**

The `plugin-skills-check` workflow's path filter does not match
`skills/setup-slack-channel/**`, so this PR would not have caught it —
it would have gone red on the next unrelated PR that touched the script
or a package skill, or silently eaten the skill on the next sync run.

Fix is two lines: add the slug to `RESERVED_LIFECYCLE_SLUGS`, and move
the paired `size` assertion in
`scripts/__tests__/sync-plugin-skills.test.ts` from 9 to 10. The test
file already documents this exact hazard in a comment.

### Conflict resolution

The only conflict was the `copilotkit-channels` frontmatter description,
which #6320 rewrote in parallel. The two sides disagreed about Teams:
this branch said the skill "assumes the provider app already exists",
while #6320 established that Teams provider setup **is** this skill's
job because the CLI or dashboard wizard performs it. The resolution
keeps this branch's code-half framing and the `setup-slack-channel`
handoff, but scopes that handoff to *first-time Slack app creation* only
— so it contradicts neither #6320's Teams sections nor the Slack
provider troubleshooting that stays in this file. Took #6320's `version:
1.1.0`.
2026-08-03 15:01:27 -07:00
Mark dd36800a47 chore: release angular v0.3.1 (#6350)
## Release angular v0.3.1

**Scope:** `angular` | **Bump:** `patch`

---

### How this release process works

1. **This PR was created automatically** by the "release / create-pr"
workflow.
   It bumped the `angular` packages to `0.3.1`
   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 `angular` packages to npm at version `0.3.1`
   - Creates git tag `angular/v0.3.1`
   - 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.
angular/v0.3.1
2026-08-03 14:14:30 -07:00
contextablemark bc968ce96b chore: release angular v0.3.1 2026-08-03 20:50:53 +00:00
Mark f1156c9125 fix(deps): patch eventsource so Bun stops breaking the runtime integration job (#6334)
## What

Fixes the intermittently-red `test / integration / runtime` **bun** leg.
Three commits, smallest blast radius first:

1. **`ci(runtime)`** — pin `bun-version` from `latest` to `1.3.14` so a
Bun release can't change module-resolution behaviour between runs. (Only
`bun-version: latest` in the repo.)
2. **`fix(deps)`** — **this is the actual fix.** Patch
`eventsource@3.0.7` to drop its `bun` export condition, via `pnpm patch`
+ `patchedDependencies`.
3. **`refactor(runtime)`** — module-graph hygiene: load the MCP SSE
transport lazily. Explicitly **not** a behaviour fix; commit 2 is.

## Root cause

```
TypeError: require() async module ".../eventsource@3.0.7/node_modules/eventsource/dist/index.js" is unsupported. use "await import()" instead.
    at .../@modelcontextprotocol/sdk/dist/cjs/client/sse.js:4:7
    at .../@ag-ui/mcp-apps-middleware/dist/index.js:1:983
    at processTicksAndRejections (unknown:7:39)
```

- `eventsource@3.0.7` maps its `bun` export condition to the **ESM**
build (`dist/index.js`). Bun resolves `bun` **before** `require`, so a
CJS `require("eventsource")` receives an async ESM module and throws.
The package ships a real CJS build (`dist/index.cjs`) behind `require`,
but Bun never reaches it.
- Two CJS consumers in our graph hit this: the MCP SDK's own
`dist/cjs/client/sse.js`, and `@ag-ui/mcp-apps-middleware@0.0.3` — a
CJS-only package (`main: ./dist/index.js`, no `exports`, no `type:
module`) that `require`s that SDK path unconditionally at module load.
- **Why intermittent:** it's a load-order race. If the ESM graph fully
evaluates `eventsource` first, the later CJS `require` can be served
synchronously and the run passes; otherwise it throws.

Dropping the `bun` key makes Bun fall through to `import` for ESM
consumers (same `dist/index.js` as before — no behaviour change) and to
`require` for CJS consumers (`dist/index.cjs`, which is what they need).
Only `bun` is touched; `deno`/`source`/`import`/`require`/`default` are
left alone.

**A version bump is not an alternative:** `eventsource@4.1.0` still
ships the same `bun` → ESM mapping.

## Patch diff

`patches/eventsource@3.0.7.patch` (header abridged — the file carries
the full rationale and an explicit deletion criterion so it doesn't
become permanent by accident):

```diff
# Drops the `bun` export condition from eventsource.
# ...
# DELETE THIS PATCH WHEN: eventsource drops the `bun` condition or points it at
# dist/index.cjs, OR Bun stops preferring `bun` over `require` for CJS requires.
diff --git a/package.json b/package.json
@@ -10,7 +10,6 @@
   "exports": {
     ".": {
       "deno": "./dist/index.js",
-      "bun": "./dist/index.js",
       "source": "./src/index.ts",
       "import": "./dist/index.js",
       "require": "./dist/index.cjs",
```

Root `package.json` gains:

```json
"patchedDependencies": { "eventsource@3.0.7": "patches/eventsource@3.0.7.patch" }
```

This repo had no `patches/` precedent (it uses `pnpm.overrides`), so
this sets one — hence the minimal one-line patch and the documented
removal criterion.

## Red-green proof

All four states. Local runs are the **same command on the same
machine**, differing only by whether the patch is applied. Bun 1.3.14,
macOS arm64, run from `packages/runtime`:

```sh
bun test src/v2/runtime/__tests__/integration/bun/bun-servers.integration.test.ts
```

A single green run proves nothing here — it's a race — so both local
states are N=20.

### 1. CI-RED

- This branch before the patch, run
[30835752558](https://github.com/CopilotKit/CopilotKit/actions/runs/30835752558)
@ `5456e308b9` — `runtime / node` success, **`runtime / bun` failure**:

```
4 | const eventsource_1 = require("eventsource");
TypeError: require() async module "/home/runner/work/CopilotKit/CopilotKit/node_modules/.pnpm/eventsource@3.0.7/node_modules/eventsource/dist/index.js" is unsupported. use "await import()" instead.
 0 pass
 1 fail
```

- Also on `main` @ `26a23bbf3a`, run
[30825667393](https://github.com/CopilotKit/CopilotKit/actions/runs/30825667393)
— same leg, same failure.

### 2. LOCAL-RED (eventsource UNPATCHED, N=20)

```
run  1:  72 pass  0 fail
run  2:   0 pass  1 fail
run  3:   0 pass  1 fail
run  4:   0 pass  1 fail
run  5:   0 pass  1 fail
run  6:   0 pass  1 fail
run  7:   0 pass  1 fail
run  8:   0 pass  1 fail
run  9:   0 pass  1 fail
run 10:  72 pass  0 fail
run 11:   0 pass  1 fail
run 12:   0 pass  1 fail
run 13:  72 pass  0 fail
run 14:   0 pass  1 fail
run 15:   0 pass  1 fail
run 16:  72 pass  0 fail
run 17:   0 pass  1 fail
run 18:  72 pass  0 fail
run 19:   0 pass  1 fail
run 20:   0 pass  1 fail
LOCAL-RED TOTAL: pass=5 fail=15  (out of 20)
```

### 3. LOCAL-GREEN (eventsource PATCHED, N=20)

```
run  1:  72 pass  0 fail
run  2:  72 pass  0 fail
run  3:  72 pass  0 fail
run  4:  72 pass  0 fail
run  5:  72 pass  0 fail
run  6:  72 pass  0 fail
run  7:  72 pass  0 fail
run  8:  72 pass  0 fail
run  9:  72 pass  0 fail
run 10:  72 pass  0 fail
run 11:  72 pass  0 fail
run 12:  72 pass  0 fail
run 13:  72 pass  0 fail
run 14:  72 pass  0 fail
run 15:  72 pass  0 fail
run 16:  72 pass  0 fail
run 17:  72 pass  0 fail
run 18:  72 pass  0 fail
run 19:  72 pass  0 fail
run 20:  72 pass  0 fail
LOCAL-GREEN TOTAL: pass=20 fail=0  (out of 20)
```

**5/20 → 20/20.**

### 4. CI-GREEN

The `test / integration / runtime` bun leg on this PR is the
load-bearing evidence. See checks below.

## Clean-install verification

A patch that only works incrementally is worthless in CI, so this was
verified from scratch — every `node_modules` in the workspace deleted,
then `pnpm install --frozen-lockfile`:

- Install exited **0** with `--frozen-lockfile` (lockfile is
self-consistent; no drift).
- Exactly one `eventsource` entry in the store, and it is the patched
one:

`node_modules/.pnpm/eventsource@3.0.7_patch_hash=427032a8df76e38f39988ff5fb919a02ccb70eb8a235e2b484007e4bebb1e67e/`
- Resolved `package.json` in the store after clean install:

`{"deno":"./dist/index.js","source":"./src/index.ts","import":"./dist/index.js","require":"./dist/index.cjs","default":"./dist/index.js"}`
— `bun` absent, everything else intact.
- Lockfile records it deterministically:
`patchedDependencies.eventsource@3.0.7` with `hash: 427032a8...` and
`path: patches/eventsource@3.0.7.patch`, and the dependency edge
resolves as `eventsource@3.0.7(patch_hash=427032a8...)`.
- `--frozen-lockfile` accepted the lockfile verbatim (it does not
rewrite), so the lockfile is self-consistent with the manifests.
- The comment header on the patch file does not break pnpm's patch
applier.
- **Lockfile diff is scoped to eventsource — 9 lines, 3 hunks, nothing
else.** An earlier revision of this branch carried incidental drift
(`vue-component-type-helpers` 3.3.8→3.3.9 and a `vite` peer-range
narrowing) picked up by a non-frozen install; that has been reverted so
the diff contains only the patch wiring.

## Tests

All from `packages/runtime`, with the patch applied:

| Suite | Command | Result |
|---|---|---|
| Full runtime suite | `pnpm exec vitest run` | **130 files / 1835 tests
passed**, 0 failed |
| Node integration (other CI leg) | `pnpm exec vitest run
src/v2/runtime/__tests__/integration/node-servers.integration.test.ts` |
**153 passed** |
| MCP + SSE transport | `pnpm exec vitest run
src/agent/__tests__/mcp-servers-integration.test.ts
src/agent/__tests__/mcp-clients.test.ts
src/v2/runtime/__tests__/mcp-apps-middleware-integration.test.ts` | **3
files / 22 passed** |
| Bun integration | `bun test .../bun-servers.integration.test.ts` |
**20/20** (was 5/20) |

Non-Bun consumers are unaffected by construction — Node never reads the
`bun` export condition — and the Node suites above confirm it. The SSE
path stays covered: `mcp-servers-integration.test.ts` exercises
`mcpServers: [{ type: "sse", url }]`, so it executes the new `await
import()`, which sits **outside** the `try/catch` that swallows
per-server connection failures.

## Module-graph proof for commit 3

Commit 3 is hygiene, so it gets its own narrower proof. Probe: Bun
populates `require.cache` with the resolved path of every module
actually loaded, so importing one module and inspecting that cache shows
whether `eventsource` entered the graph. Two controls run every time so
it can't pass vacuously.

```ts
const target = process.argv[2]!;
await import(target);
const keys = Object.keys(require.cache).filter(
  (k) => /eventsource/.test(k) && !/eventsource-parser/.test(k),
);
console.log(`${target}\n  eventsource loaded: ${keys.length > 0 ? "YES" : "NO"}`);
```

| Module | before commit 3 | after commit 3 |
|---|---|---|
| `@copilotkit/shared` (negative control) | NO | NO |
| `@modelcontextprotocol/sdk/client/sse.js` (positive control) | YES |
YES |
| `../src/agent/index.ts` (subject, non-SSE path) | **YES** | **NO** |

Both controls hold steady; only the subject flips. Measured on its own,
commit 3 does **not** move the bun pass rate (5/20 before, 3/20 after
within noise) — which is exactly why commit 2 exists.

## Typing

No `as any`, no `@ts-ignore`. `const { SSEClientTransport } = await
import(...)` keeps the class fully typed — TypeScript resolves
dynamic-import types statically. `packages/runtime/tsconfig.json`
already sets `"module": "es2022"` with the comment *"so dynamic import()
typechecks"*, so the pattern is anticipated.

Two adjacent bare `let` declarations (`transport`, `mcpClient`) gained
explicit annotations (`MCPTransport | undefined`, `MCPClient`) because
editors surface them as implicit-any suggestions. Both pre-existed on
`main`. Verified: `tsc --noEmit` clean; `tsc --noEmit --strict` error
set **identical to baseline** (3 pre-existing unrelated `TS2769`s);
`oxlint` warnings **unchanged from baseline** (2, both pre-existing).

`SSEClientTransport` is `@deprecated` in SDK 1.29.0 in favour of
`StreamableHTTPClientTransport`. That deprecation pre-exists on `main`
and is left alone: `type: "sse"` is documented public config, SSE and
Streamable HTTP are different wire protocols, and the SDK's own note
says clients "may need to support both transports during the migration
period." Migrating is a user-facing change for its own PR.

## Gates run

- `pnpm exec oxfmt --check packages/runtime/src/agent/index.ts` — clean
- `pnpm exec oxlint packages/runtime/src/agent/index.ts` — 0 errors, 2
warnings (both pre-existing on `main`)
- `pnpm nx run @copilotkit/runtime:check-types` — pass
- `pnpm exec commitlint --from HEAD~3 --to HEAD` — pass
- `pnpm install --frozen-lockfile` from a fully wiped workspace — exit 0
2026-08-03 13:33:48 -07:00
Tyler Slaton 34b81a3657 chore: release monorepo v1.66.0 (#6348)
## Release monorepo v1.66.0

**Scope:** `monorepo` | **Bump:** `minor`

---

### How this release process works

1. **This PR was created automatically** by the "release / create-pr"
workflow.
   It bumped the `monorepo` packages to `1.66.0`
   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.66.0`
   - Creates git tag `monorepo/v1.66.0`
   - 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.66.0
2026-08-03 13:23:06 -07:00
tylerslaton a87b77a991 chore: release monorepo v1.66.0 2026-08-03 20:14:52 +00:00
Tyler Slaton d44b6c8e92 chore: release channels v0.7.0 (#6345)
## Release channels v0.7.0

**Scope:** `channels` | **Bump:** `minor`

---

### How this release process works

1. **This PR was created automatically** by the "release / create-pr"
workflow.
   It bumped the `channels` packages to `0.7.0`
   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 `channels` packages to npm at version `0.7.0`
   - Creates git tag `channels/v0.7.0`
   - 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.
channels/v0.7.0
2026-08-03 13:02:31 -07:00
tylerslaton 53bf978904 chore: release channels v0.7.0 2026-08-03 19:52:48 +00:00
GeneralJerel bc5f807351 fix(skills): correct the last two stale interactivity claims
The previous pass fixed three of the sites and missed the ones that do not
contain the string `is_enabled` — a grep keyed on that phrase could not see
either.

`references/slack-workspace-and-app.md:109` is the one that mattered. It sat in
a table headed "Settings that must stay as the manifest sets them" and said
Interactivity must be `disabled`, 50 lines below the corrected prose saying the
opposite. That is worse than the bug it replaced rather than equivalent to it:
the prose only told a reader a feature was broken, whereas a normative settings
table under a keep-this-as-is heading gets acted on mechanically — and acting on
it turns interactivity off, causing the exact failure the rest of the fix
prevents. It now names the enabled state and the interactivity request URL
(`/api/channels/adapters/slack/interactivity`, verified against Intelligence
`libs/channels-setup/src/slack.ts:14-18`), and says modals stay undelivered
either way.

`assets/slack-app-manifest.yaml:33-34` carried the same claim in a comment —
"the managed path does not deliver interactive payloads at all." Not raised in
review; found by re-grepping for `nteractiv` instead of the specific phrasing.
The comment now distinguishes the direct-adapter shape (interactivity enabled,
no request URL) from the managed one (enabled with an Intelligence request URL),
which is the distinction the whole file exists to draw.

Swept for every remaining variant of the claim; none left.
2026-08-03 12:23:35 -07:00
Mark 9e08421653 fix(a2ui-renderer): bump @a2ui/web_core to 0.10.4 for openUrl XSS (#6343)
Closes the `openUrl` XSS reported against `@a2ui/web_core`
([GHSA-72qq-p3r5-f7wq](https://github.com/a2ui-project/a2ui/security/advisories/GHSA-72qq-p3r5-f7wq),
CVSS 9.3).

## The vulnerability

`@a2ui/web_core` <= 0.10.1 passed an agent-supplied `openUrl` argument
straight to `window.open()` with no scheme allowlist:

```js
// basic_catalog/functions/basic_functions.js — 0.9.0
if (args.url && typeof window !== 'undefined' && window.open) {
    window.open(args.url, '_blank');   // no scheme check
}
```

A malicious agent could emit a Button whose `functionCall` named a
`javascript:` URI; clicking it executed arbitrary script in the host
application's origin. The Basic Catalog is the default, so no
non-default configuration was required to be exposed.

## Why it reached us

We pinned `0.9.0` **exactly**, as a runtime `dependencies` entry of two
published packages — so downstream users could not upgrade out of it
without an `overrides` entry:

| Published package | Path to the vulnerable version |
|---|---|
| `@copilotkit/a2ui-renderer` | direct pin `0.9.0` |
| `@copilotkit/vue` | direct pin `0.9.0` |
| `@copilotkit/react-core` | → `a2ui-renderer` |

We import the sink deliberately (`BASIC_FUNCTIONS`) in four places
across the React, Lit, and Vue catalogs, and add no sanitisation of our
own. Note the advisory enumerates three affected renderers (React, Lit,
Angular); we ship a fourth, Vue, that upstream did not list.

## The change

Bump to `0.10.4`, which adds a strict http/https allowlist plus
`noopener,noreferrer`. This is a drop-in upgrade: `0.10.4` still exports
the `./v0_9` and `./v0_9/basic_catalog` entrypoints we import, and of
the `v0_9` surface (165 → 194 exports) the only symbol removed is
`FrameworkSignal`, which is referenced nowhere in this repo.

`showcase/angular` and `examples/v2/angular/demo` are private; those
bumps are hygiene only.

## Tests

Adds 6 regression tests over the React and Lit renderers, which reach
the sink independently of each other. They assert that `javascript:` and
`data:` URIs never reach `window.open`, that https URLs still open with
`noopener,noreferrer`, and that a blocked scheme leaves the surface
mounted rather than escaping into the click handler.

These were verified to be non-vacuous: pinned back to `0.9.0`, **5 of
the 6 fail**, including direct confirmation that `javascript:alert(1)`
reaches `window.open` through our own renderer on the vulnerable
version.

Full suites green: `a2ui-renderer` 22, `vue` 1074, `react-core` 1471,
`runtime` 1835, `angular` 292, `react-native` 251. Builds and
type-checks clean.

## Behaviour change worth knowing

`0.10.x` changes `openUrl`'s failure mode: the old code silently no-op'd
on a bad URL, the patched one throws `A2uiExpressionError` for a
non-http(s) scheme. That throw does **not** reach the render path —
`web_core`'s own `evaluateFunctionReactive` already catches it and
routes it to `surface.dispatchError`. Confirmed by exercising a real
click in both renderers: nothing escapes, no uncaught error, the surface
stays mounted.

## Follow-ups (not in this PR)

- **`@copilotkit/angular@0.3.0` remains exposed.** It pins
`@copilotkit/a2ui-renderer@1.63.2`, which pins the vulnerable `0.9.0`.
It needs a release after `a2ui-renderer` publishes, or Angular users
stay on the vulnerable transitive.
- **Blocked actions are invisible.** The resulting `EXPRESSION_ERROR` is
emitted on `surface.onError`, which no renderer subscribes to — so an
agent probing `javascript:` URIs is blocked completely silently, with no
log or telemetry. Surfacing it is a cross-renderer API decision,
deliberately kept out of a security bump.
2026-08-03 12:09:07 -07:00
Sam Julien 5d802f3932 docs(channels): reconcile launch documentation (#6335)
## Summary

This PR reconciles the Channels documentation with the released Channels
SDK and Runtime behavior, recent CopilotKit and Intelligence changes,
and the launch review of the provider docs.

The scope is intentionally limited to Channels guides, provider routing,
Channels SDK reference pages, and regression coverage in
`showcase/shell-docs`.

## Why

The existing docs mixed older package versions and pre-launch
assumptions with newer SDK behavior. In particular:

- examples still referenced Channels SDK `0.5.0` / `0.6.0` and Runtime
`1.64.2`
- lifecycle guidance did not distinguish eager Node/Express startup from
lazy Hono/generic Fetch startup
- Slack setup omitted current interactivity and file-scope requirements
- routing, welcome-event, reply-continuation, event-sanitization, clone,
and file-identifier behavior had changed or lacked precise documentation
- identity and Memory were not documented as a complete provider-scoped
journey
- scaling and HITL guidance overstated public configuration and
cross-backend support
- Channels CLI support is not yet part of the released public setup path
and should not be presented as available

## What changed

### Released versions and setup paths

- updates Channels examples to SDK `0.6.1` and Runtime `1.65.0`
- keeps the Intelligence browser wizard as the documented released setup
path
- excludes Channels CLI instructions until that support ships in a
public release
- preserves the latest browser-based Teams wizard details for draft
creation, branding/package handling, permissions, installation state,
and runtime verification
- updates Slack setup to use a bot token plus Signing Secret, enable
Interactivity, and include `files:read` / `files:write`
- tells existing Slack app owners where to obtain the current generated
manifest, when to reinstall, and when to refresh the bot token

### Identity and Memory

- adds one shared `Identity and Memory` source guide exposed only
through provider-scoped routes:
  - `/slack/identity-and-memory`
  - `/teams/identity-and-memory`
- does not introduce a channel-agnostic documentation surface
- separates conversation, current provider actor, and canonical
application user
- provides provider-specific Slack and Teams identity mapping examples
without leaking the other provider's identifiers into the rendered page
- documents safe per-run user/project Memory grants, unlinked-user
behavior, and approval resume subjects
- replaces the incomplete approval snippet with a complete
registered-component callback example
- adds a verification sequence for multi-actor conversations, unlinked
actors, and initiator-versus-actor approval behavior
- corrects the `channel_memory_unavailable` description to reflect the
runtime/adapter capability check
- cross-links the guide from both provider quickstarts,
thread/transcript guidance, and SDK reference content

### Runtime lifecycle and routing

- documents that Node and Express listeners start the Channel eagerly
- documents lazy startup for Hono and generic Fetch adapters
- clarifies when `ready()` is optional versus required
- places signal-handler registration before readiness
- corrects connecting-status expectations
- documents the single-path routing rules for mentions and ordinary
messages
- describes `onWelcome` as a lifecycle event rather than a synthetic
user message

### SDK reference corrections

- documents reply-continuation defaults and truncation behavior:
  - 11,000 UTF-8 bytes
  - 20 messages
- narrows `sanitizeAgentEvents` guidance to the known `parentMessageId`
repair
- documents per-turn agent cloning, including factory results, and the
`0.6.1` warning behavior
- distinguishes `assetId` from provider `fileId` in `Thread.postFile()`
- adds a current direct Slack adapter example
- updates command and reaction coverage for the current SDK surface
- keeps detailed option semantics in the `createChannel` function
reference and links to it from the `Channel` class page to reduce
duplication

### Production and HITL guidance

- removes the nonexistent public `maxConcurrentDeliveries` option
- describes the runtime's internal bounded delivery capacity without
presenting it as user configuration
- names the validated managed approval path precisely: a DeepAgent
tool-driven `on_interrupt` that returns from delivery and resumes on a
later interaction
- gives other backends an explicit real-provider verification checklist
instead of implying universal native AG-UI interrupt compatibility
- clarifies that event sanitization does not create framework interrupt
support

### Regression coverage

- adds route tests for both provider-scoped identity-and-memory pages
- adds documentation assertions for versions, lifecycle, Slack manifest
requirements, routing, SDK behavior, scaling/HITL claims,
provider-specific identity examples, verification steps, and cross-links
- keeps a broad guard preventing unreleased Channels CLI commands from
entering the public setup journey without enumerating future command or
configuration details
- makes wording assertions tolerant of normal MDX line wrapping

## Rebase reconciliation

The branch is rebased onto current `origin/main` (`0c72359cbd`). The
rebase included overlapping changes to the Intelligence setup guide. The
resolution retains the newer browser-based Teams setup improvements
while excluding the CLI-only path so the page remains aligned with the
released public setup surface.

## User impact

Readers get setup instructions that match the released product, more
precise lifecycle and SDK behavior, and a complete provider-scoped
identity/Memory journey. Existing Slack users can find and apply the
current generated manifest, approval implementers get a testable
compatibility boundary, and users are not directed to unreleased CLI
commands.

## Scope boundaries

This PR does **not**:

- change Channels SDK or Runtime implementation code
- document unreleased CLI commands
- introduce channel-agnostic Channels pages
- modify unrelated documentation
- commit generated registry, catalog, setup-content, or search-index
churn

## Validation

From the repository root:

- `pnpm exec oxfmt --check showcase/shell-docs/next.config.ts
showcase/shell-docs/src/lib/channel-guide-routes.ts
showcase/shell-docs/src/lib/__tests__/channel-guide-routes.test.ts
showcase/shell-docs/src/lib/__tests__/channels-docs.test.ts`
- `git diff --check origin/main...HEAD`
- publication-safety scan of added lines for credentials, private Slack
references, internal email addresses, and private keys
- scan confirming Channels CLI commands and unreleased setup details are
absent from public Channels docs and regression tests

From `showcase/shell-docs`:

- `npm run lint` — 0 errors; existing package warnings remain unchanged
- `npm run typecheck`
- `./node_modules/.bin/vitest run --maxWorkers=1 --no-file-parallelism`
— 54 files, 368 tests passed
- `npm run build` — production build completed; 222 pages generated

Local rendered-route verification:

- `/slack/identity-and-memory` — HTTP 200
- `/teams/identity-and-memory` — HTTP 200
- `/slack/intelligence` — HTTP 200
- `/teams/intelligence` — HTTP 200

The worktree is clean, and the local review server remains available at
`http://localhost:3003`.
2026-08-03 12:07:09 -07:00
Sam Julien 2cc279b4e9 test(channels): tolerate wrapped setup copy 2026-08-03 11:59:04 -07:00
Sam Julien 9ca0727a08 docs(channels): refine launch guidance 2026-08-03 11:53:33 -07:00
Sam Julien 9910ac9293 docs(channels): reconcile launch documentation 2026-08-03 11:53:32 -07:00
GeneralJerel 77e5415c45 fix(skills): correct stale Slack capability claims and narrow trigger scope
Addresses review on #6340.

Interactivity is no longer disabled on the managed path. The shared generator
emits `interactivity.is_enabled: true` with an Intelligence-hosted request URL
(Intelligence `libs/channels-setup/src/slack.ts:209-211`) and the ingress
handles `block_actions` (`apps/app-api/src/routes/channels-routes.ts:868`), so
HITL buttons and selects do fire. The skill's own bundled manifest asset already
said `is_enabled: true`, so the prose contradicted the file shipped beside it.
What is still undelivered is `slash_commands` (absent from the generator) and
`view_submission` (`apps/app-api/src/channels/slack-ingress.ts:1050`), so the
`onCommand` / `onModalSubmit` warnings stay. Corrected in all three places that
claimed otherwise, and the troubleshooting entry now tells the reader a dead
button is a real failure rather than a capability limit.

Browser-only framing is now a routing instruction rather than an architectural
claim, since `copilotkit channels add` does create the Channel and attach the
adapter. Same outcome, but it no longer contradicts `--help` for an agent that
was told to check it.

Trigger scope is narrowed in the frontmatter description instead of rewriting
Phase 0. The phases assume OpenTag conventions (`app/channel.tsx`, `app/env.ts`,
`INTELLIGENCE_CHANNEL_NAME`, an agent on port 8123), which are not what
`copilotkit init` scaffolds — naming that in the description keeps the skill from
firing on any "connect my agent to Slack" once it installs into customer repos.

Also widens the plugin-skills-check path filter to `skills/**` rather than
adding the one new slug. The orphan scan reads the whole mirror, so enumerating
individual directories is what let this PR's own blocker go untested and would
have armed it again for the next standalone skill.
2026-08-03 11:53:20 -07:00
Mike Ryan 0c72359cbd Support Slack data visualization blocks (#6342)
## What does this PR do?

Slack data visualization blocks were listed in the native catalog, but
the JSX surface emitted a non-Slack `visualizations` field and had no
typed `chart` prop. This PR makes `Slack.Block.DataVisualization`
produce the payload that Slack documents.

- Adds public types for pie, bar, area, and line chart payloads.
- Requires `title` and `chart` at compile time and runtime.
- Checks Slack limits for titles, labels, segments, series, points,
categories, axis labels, positive pie values, unique series names, and
exact category coverage.
- Rejects more than two data visualization blocks in one message.
- Preserves the chart through direct Slack `chat.postMessage` delivery
and managed Intelligence delivery.
- Documents a small `defineChannelComponent` weather chart example.

Slack contract:
https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block/

## Review path

1. Start with `packages/channels-slack/src/native.ts` for the public JSX
and TypeScript contract.
2. Read `packages/channels-slack/src/data-visualization.ts` for runtime
checks.
3. Read `packages/channels-slack/src/native-data-visualization.test.tsx`
for the weather component through the real adapter boundary.
4. Read
`packages/channels-slack/src/native-data-visualization-validation.test.ts`
for provider limit and cross-field cases.
5. Read
`packages/channels-intelligence/src/delivery-provider-elements.test.ts`
for the managed effect payload.

## Test coverage

- All four chart variants serialize to exact Slack JSON.
- Invalid nested payloads fail before a network request.
- Two charts pass and three charts fail.
- Negative values pass for series charts; non-positive values fail for
pie charts.
- Compile-time tests reject missing fields, unsupported chart types,
wrong chart shapes, and children.
- A `defineChannelComponent` weather card reaches
`SlackAdapter.client.chat.postMessage` with the expected Block Kit
request.

## Validation

- `NX_DAEMON=false pnpm nx run-many -t test,check-types,build
--projects=@copilotkit/channels-slack,@copilotkit/channels-intelligence`
- `NX_DAEMON=false pnpm nx run-many -t publint,attw
--projects=@copilotkit/channels-slack,@copilotkit/channels-intelligence`
- `NX_DAEMON=false pnpm verify:channels-umbrella`
- `pnpm check:channel-native-catalogs && pnpm
audit:channel-native-catalogs`
- `pnpm exec oxfmt --check packages/channels-slack/README.md`

This checkout has no `docs:check` script. The changed README passes the
repo formatter, and its executable example is covered by the adapter
test.

## Related PRs and Issues

- Follows the native Slack JSX surface merged in
https://github.com/CopilotKit/CopilotKit/pull/6331

## Checklist

- [x] 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 enabled
2026-08-03 11:45:23 -07:00
Mark 36f2972150 fix(a2ui-renderer): bump @a2ui/web_core to 0.10.4 for the openUrl XSS advisory
GHSA-72qq-p3r5-f7wq (CVSS 9.3). web_core <= 0.10.1 passed an agent-supplied
`openUrl` argument straight to `window.open()` with no scheme allowlist, so a
Button whose `functionCall` named a `javascript:` URI executed arbitrary script
in the host origin when a user clicked it. The Basic Catalog is the default, so
no non-default configuration was required to be exposed.

We pinned 0.9.0 exactly, as a runtime dependency of two published packages
(@copilotkit/a2ui-renderer, @copilotkit/vue) and transitively of
@copilotkit/react-core and @copilotkit/angular, so downstream users could not
upgrade out of it on their own. 0.10.4 keeps the ./v0_9 and
./v0_9/basic_catalog entrypoints we import; the only symbol dropped from v0_9
is FrameworkSignal, which we never referenced.

Add regression tests over both renderers that reach the sink independently
(React and Lit). They assert that javascript: and data: URIs never reach
window.open, that https URLs still open with noopener,noreferrer, and that a
blocked scheme leaves the surface mounted rather than escaping into the click
handler. Verified they fail against 0.9.0 and pass against 0.10.4.
2026-08-03 18:43:00 +00:00
github-actions[bot] 00f16379c9 style: auto-fix formatting 2026-08-03 18:32:49 +00:00
GeneralJerel 15cfce0859 chore(skills): give setup-slack-channel a version field
Every other standalone skill in RESERVED_LIFECYCLE_SLUGS carries one; only
the package-mirrored skills (runtime, react-core, a2ui-renderer) omit it.
This makes the new skill consistent with its cohort.

Nothing enforces the field, so this is convention rather than a gate. It does
mean the skill is no longer byte-identical to the channels-sdk source, so the
PR description is updated to say "unchanged except for an added version field"
rather than claiming a clean diff -r.
2026-08-03 11:30:27 -07:00
Mike Ryan 979a8ee990 feat(channels-slack): support data visualization blocks 2026-08-03 11:29:12 -07:00
GeneralJerel d51fe15c71 Merge branch 'main' into feat/channel-setup-skills
Resolves the one conflict in skills/copilotkit-channels/SKILL.md, where main
(#6320) rewrote the same frontmatter description this branch narrowed.

The two sides disagreed on Teams. This branch scoped the skill to the code half
and said it "assumes the provider app already exists"; main established that
Teams provider setup *is* this skill's job, because the CLI or dashboard wizard
performs it. Kept the branch's code-half framing and the handoff to
setup-slack-channel, but scoped that handoff to first-time Slack app creation
only, so it no longer contradicts main's Teams sections or the Slack provider
troubleshooting that stays in this file. Took main's version 1.1.0.

Also registers setup-slack-channel in RESERVED_LIFECYCLE_SLUGS. Standalone
skills have no packages/*/skills source, so without an entry the sync script
treats the directory as an orphan: `pnpm check:plugin-skills` fails, and
`pnpm sync:plugin-skills` deletes all 8 files of the new skill. Verified both
behaviours against the pre-fix script before fixing. The paired size assertion
in the unit test moves 9 -> 10.
2026-08-03 11:17:09 -07:00
Jordan Ritter 67ec66be0d refactor(runtime): load the MCP SSE transport lazily
Module-graph hygiene, not a behaviour fix -- the preceding eventsource patch is
what fixes the bun failure.

The SDK's SSE transport was imported at the top of the agent module but is only
constructed inside the `type === "sse"` branch ~1300 lines below, so
`eventsource` was pulled into the module graph of every non-SSE path, including
every test that merely touches the agent module. Move it to an `await import()`
at the point of use.

`transport` and `mcpClient` gain explicit annotations so they keep real types
instead of the bare `let` declarations they had before.
2026-08-03 10:48:14 -07:00
Jordan Ritter 6a8dc4ec50 fix(deps): patch eventsource to drop its bun export condition
eventsource maps its `bun` export condition to the ESM build, and Bun resolves
`bun` before `require`. So a CJS require("eventsource") under Bun receives an
async ESM module and throws "require() async module ... is unsupported". The
package ships a real CJS build behind `require`, but Bun never reaches it.

Two CJS consumers in our graph hit this: the MCP SDK's own dist/cjs/client/sse.js,
and @ag-ui/mcp-apps-middleware, which requires that SDK path unconditionally at
module load. It surfaced as an intermittent failure of the runtime bun
integration job -- intermittent because it is a load-order race, where the run
only passes if the ESM graph happens to evaluate eventsource first.

Dropping the `bun` key makes Bun fall through to `import` for ESM consumers
(same file as before) and `require` for CJS consumers (the CJS build they need).
Takes the bun integration test from 5/20 to 20/20 locally. A version bump is not
an alternative: eventsource 4.1.0 still ships the same mapping.
2026-08-03 10:48:14 -07:00
Jordan Ritter a9f98314d0 ci(runtime): pin Bun to 1.3.14 for the integration job
`bun-version: latest` let a Bun release change module-resolution behaviour
between runs. 1.3.14 is the version the recent passing and failing runs both
resolved, so pin it and make the job reproducible.
2026-08-03 10:48:14 -07:00
Tyler Slaton 7f37c3395e fix(channels-intelligence): restore inbound trigger files (#6332)
## Problem

Channel agents lose inbound files whenever the current-trigger
transcript omits attachments. The currently deployed Intelligence path
always omits those files because normalized_payload never contains their
handles.

## Why

The delivery adapter seeds the current inbound turn from the transcript,
and core then deduplicates the explicit prepared input. Files present
only on the prepared delivery therefore never reach either the
agent-history consumer or channel.getMessages during version skew.

## Fix

Restore a missing current-trigger transcript file list from the prepared
delivery inside ClaimedChannelDelivery.getTranscript(), where the result
is shared and memoized for both consumers. Existing transcript files are
preserved, so the Intelligence fix and this fallback cannot duplicate
attachments.

Either PR independently repairs the agent path. Coverage proves both an
omitted transcript and an already-correct transcript hydrate the image
for getMessages and agent seeding.
2026-08-03 10:43:41 -07:00
Tyler Slaton ebace44a9a feat(channels): add native channel JSX (refs OSS-655) (#6331)
## Summary

- add `defineChannelComponent` so an agent can call a server-rendered
JSX component as a typed tool
- add native JSX namespaces for Slack Block Kit and Teams Adaptive Cards
- use one provider codec for both direct adapters and
Intelligence-managed delivery
- recover interactive handlers by stable JSX key after a process restart
- generate and audit the native component catalog against the provider
catalogs

This keeps native provider UI in the existing Channels render and
delivery path. It does not add a second renderer, transport, or action
system.

## Review order

1. **Component tool contract:**
`packages/channels-core/src/channel-component.ts`, `create-channel.ts`,
and `thread.ts`
   - Standard Schema validates agent arguments before render.
   - Render receives the source platform and run `AbortSignal`.
- The rendered UI posts as a separate provider message; the tool returns
a short acknowledgement.
2. **Native IR:** `packages/channels-ui/src/native.ts` and `render.ts`
   - Native nodes carry a provider tag.
- Traversal follows named slots such as Slack `accessory` and Teams
`actions`, not only `children`.
3. **Slack:** `packages/channels-slack/src/native*.ts`, `render.ts`, and
`interaction.ts`
- `Slack.Block`, `Slack.Element`, and `Slack.Object` map to Block Kit
field names.
- Direct and managed Slack share the same codec and fallback-text rules.
4. **Teams:** `packages/channels-teams/src/native*.ts`,
`render/index.ts`, and `interaction.ts`
   - `Teams.AdaptiveCard` is the explicit root.
- The serializer computes the minimum Adaptive Card version from every
type and property used.
5. **Recovery and managed parity:**
`packages/channels-core/src/action-*.ts` and
`packages/channels-intelligence/src/delivery-adapter.ts`
- Stable JSX keys, the source platform, and the action value are stored
in the action snapshot.
- CopilotKit/Intelligence#729 asserts the final Slack Web API and Bot
Framework request bodies.

## Data flow

```text
agent tool call
  -> Standard Schema validation
  -> async JSX render
  -> portable or provider-native Channel IR
  -> Slack or Teams codec
  -> direct adapter or Intelligence-managed delivery
  -> provider API
```

```text
provider interaction
  -> provider callback decoder
  -> hot ActionRegistry lookup
  -> ActionStore snapshot fallback
  -> component re-render
  -> stable keyed handler
```

## Public API

An agent-rendered component uses the same JSX vocabulary as
`thread.post`:

```tsx
const Approval = defineChannelComponent({
  name: "show_approval",
  description: "Post an approval request.",
  parameters: z.object({ title: z.string() }),
  render: ({ title }, { platform }) => (
    <Card title={`${title} (${platform})`}>
      <Button key="approve" value="approve" onClick={approve}>
        Approve
      </Button>
    </Card>
  ),
});

createChannel({
  name: "approvals",
  components: [Approval],
});
```

Use native JSX only when the portable vocabulary does not expose a
provider feature:

```tsx
await thread.post(
  <Slack.Block.Section
    text={<Slack.Object.MarkdownText text="*Deploy ready*" />}
    accessory={
      <Slack.Element.Button
        key="approve"
        text={<Slack.Object.PlainText text="Approve" />}
        value={{ decision: "approve" }}
        onClick={({ action }) => approve(action.value)}
      />
    }
  />,
);
```

```tsx
await thread.post(
  <Teams.AdaptiveCard fallbackText="Deploy approval">
    <Teams.TextBlock text="Deploy ready" wrap />
    <Teams.ActionSet>
      <Teams.Action.Submit
        key="approve"
        title="Approve"
        value={{ decision: "approve" }}
        onSubmit={({ action }) => approve(action.value)}
      />
    </Teams.ActionSet>
  </Teams.AdaptiveCard>,
);
```

## Guardrails

- Native nodes from one provider fail if rendered for another provider.
- Slack rejects missing required fields, invalid top-level nodes, and
more than 50 blocks.
- Teams rejects invalid roots and explicit versions below the minimum
required version.
- Interactive nodes in agent-rendered components require stable, unique
JSX keys.
- `Slack.Raw` and `Teams.Raw` accept reviewed provider JSON but do not
bind callbacks.

The generated catalog is in `packages/channels/native-catalogs.md`. The
package READMEs contain the full Slack, Teams, and component-tool usage
notes.

## Test map

| Contract | Main coverage |
| --- | --- |
| component tool schema, render context, post, and acknowledgement |
`packages/channels-core/src/channel-component.test.ts` |
| native IR, provider tags, and named-slot traversal |
`packages/channels-ui/src/native.test.tsx` |
| Slack catalog, serialization, validation, and callbacks |
`packages/channels-slack/src/native-*.test.*` |
| Teams catalog, versioning, serialization, and callbacks |
`packages/channels-teams/src/native-*.test.*` |
| keyed cold recovery and reaction recovery |
`packages/channels-core/src/*recovery.test.*` |
| managed codec parity |
`packages/channels-intelligence/src/delivery-provider-elements.test.ts`
and CopilotKit/Intelligence#729 |

## Validation

- `pnpm nx run-many -t test,check-types,build
--projects=@copilotkit/channels-ui,@copilotkit/channels-core,@copilotkit/channels-slack,@copilotkit/channels-teams,@copilotkit/channels-intelligence,@copilotkit/channels`
- `pnpm verify:channels-umbrella`
- `pnpm check:channel-native-catalogs`
- `pnpm audit:channel-native-catalogs`
- pre-commit tests, publint, and API Extractor checks for 27 affected
projects
- all PR checks pass on `b88f9b7e4f247939d65603d96df26090baad916a`
2026-08-03 10:42:19 -07:00
Tyler Slaton 6120cebebe docs(channels): document Teams one-command setup (#6320)
## Summary

Document the draft-first Microsoft Teams setup flow across Channels
docs, skills, and the Teams adapter README.

## Why

Intelligence now offers a resumable Fast CLI path and a Guided manual
path while keeping custom branding artifacts local and separating
provider completion from runtime health.

## How

- Describe the fully scoped provisioning and resume contract.
- Replace Azure Bot and manifest-editing guidance with Teams Developer
Portal plus Entra.
- Teach both setup skills the local-only artifact and Team-installation
boundaries.
- Update documentation contract tests for the new path.
2026-08-03 10:40:35 -07:00
GeneralJerel ad5fc1bab5 feat(skills): add setup-slack-channel and split it from copilotkit-channels
Ports the setup-slack-channel skill from CopilotKit/channels-sdk into the
skill set that `copilotkit skills install` distributes, so the Slack setup
flow is reachable from the CLI rather than only from a channels-sdk checkout.

The skill is copied unchanged. It stays browser-first and makes no reference
to the `copilotkit channels` commands: per Ben Taylor on 2026-08-03, those
defer to the web app until they have more real-world usage.

Both frontmatter descriptions are narrowed so the two skills stop matching the
same request. copilotkit-channels now owns the code half — declaring, wiring,
and customising a Channel — and assumes the provider app exists.
setup-slack-channel owns the provider half for a first-time Slack setup. Each
names the other's territory and hands off.

Refs CopilotKit/channels-sdk#10
2026-08-03 10:33:26 -07:00
Tyler Slaton 65150a683b fix(channels-intelligence): repair all transcript consumers 2026-08-03 09:26:04 -07:00
Mike Ryan b88f9b7e4f feat(channels): complete native JSX contracts 2026-08-03 09:23:15 -07:00
Mike Ryan f8145b05b7 feat(channels): add native Slack and Teams JSX 2026-08-03 09:23:15 -07:00
Mike Ryan fa92ebcf44 feat(channels): recover actions by stable JSX key 2026-08-03 09:23:15 -07:00
Mike Ryan 8707d8ce12 feat(channels): add agent-rendered component tools 2026-08-03 09:23:15 -07:00
Tyler Slaton 135a614631 docs(channels): name the short-scoped Slack token as its own silent failure (#6330)
## What

Documents a Slack setup failure that passes every check we have, in the
two places that would have prevented it.

- `skills/copilotkit-channels` gets a new section under the existing
silent-failure guidance, and its verify checklist now says the app must
be **reinstalled**, not installed.
- `examples/slack/README.md` had the wrong button label and the wrong
order: *"OAuth & Permissions → **Install to Workspace** → copy the
`xoxb-` bot token."*

No code changes.

## Why

Measured against a real workspace: creating a Slack app from a manifest
**installs it**, and that install grants exactly two scopes —
`channels:history` and `chat:write`. The manifest's declared scopes
reach the app's configuration but not the grant, which is what Slack's
yellow *"you've changed the permission scopes"* banner is reporting. One
**Reinstall to Workspace → Allow** raises the grant to the full declared
set.

A bot token copied before that reinstall is the trap, because nothing
catches it:

- `auth.test` succeeds, so the credential stores and the adapter reports
healthy.
- `chat:write` is present, so the bot can post — it does not look
broken.
- `app_mentions:read` is absent, so Slack never delivers `app_mention`,
and no handler ever runs.

The result is a Channel that is genuinely online and structurally deaf.

The channels skill already documented an "online but silent" failure
whose cause is a version disagreement between the installed
`@copilotkit/channels-*` packages and the Intelligence deployment. That
one is identifiable by a rejected-delivery log line. This one logs
**nothing at all**, because Slack never sends anything to reject — so it
needed its own section rather than a footnote on that one, and the
distinguishing signal (a log line vs. no log line) is stated explicitly.

`examples/slack` is the self-hosted adapter path rather than managed
Channels, so the skill deliberately does not cover it — but the Slack
behaviour is identical, and that manifest declares more scopes than the
managed one (`users:read.email`, `team:read`, `chat:write.public`, plus
a user token), so the gap there is larger.

## Notes for review

- The two-scope measurement was taken against the managed Intelligence
manifest. The mechanism is Slack's create-from-manifest flow, which is
the same flow `examples/slack` uses, so I expect the same grant there —
but the README wording says "only a couple of the scopes the manifest
declares" rather than naming a count, since I have not measured that
manifest specifically.
- Intelligence now refuses a short-scoped token when it is pasted
(`CHANNEL_ADAPTER_SLACK_TOKEN_SCOPES_INCOMPLETE`), naming the absent
scopes. The skill says to read that error as this problem caught early,
and notes that a Channel attached before that check existed can still be
sitting in this state — only a rotation clears it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-03 09:12:00 -07:00
Tyler Slaton 6c2c289d85 fix(channels-intelligence): restore prepared trigger files 2026-08-03 08:52:57 -07:00
Benjamin Taylor b9ea51e819 docs(channels): name the short-scoped Slack token as its own silent failure
Slack installs an app when it creates one from a manifest, and that install
grants two scopes: channels:history and chat:write. The manifest's declared
scopes reach the app's configuration but not the grant, which is what Slack's
"you've changed the permission scopes" banner reports. One Reinstall to
Workspace raises the grant to the full set. Measured against a real workspace.

A token copied before that reinstall passes every check we have. auth.test
succeeds, so attaching stores it and reports the adapter healthy. chat:write is
present, so the bot can post. app_mentions:read is absent, so Slack never
delivers app_mention and no handler ever runs — an online, structurally deaf
Channel.

The channels skill already documents an "online but silent" failure caused by a
version disagreement, which logs a rejected delivery. This one logs nothing at
all, because Slack never sends anything to reject, so it gets its own section
next to it and the verify checklist now says "reinstalled" rather than
"installed". Intelligence refuses a short token at paste time now, so the
section also says to read that error as this problem caught early.

examples/slack said "Install to Workspace → copy the xoxb- bot token", which is
both the wrong button label and the wrong order. Its manifest declares even more
scopes than the managed one, so the gap there is larger.
2026-08-03 10:37:00 -05:00
Tyler Slaton 84d1caaa58 feat(shell-docs): launch Channels activation experience (#6276)
## Summary

- add disabled, branded coming-soon entries for Discord, WhatsApp,
Telegram, and SMS in the Channels picker
- add a reusable Channels activation strip to the Shell Docs landing
page with verified channel/backend guide routing, accessible selection
controls, prompt copying, OpenTag guidance, and analytics
- replace the global course banner with a Channels announcement linking
to `/channels`
- add focused coverage for route resolution, selection behavior,
clipboard feedback, keyboard navigation, telemetry, and banner content

## Validation

- `npm exec -- oxfmt --check src/components/banners.tsx
src/components/__tests__/banners.test.tsx`
- `npm run lint` (no errors; existing warnings only)
- `npm run typecheck`
- `npm test -- --maxWorkers=2` — 54 files, 362 tests passed
- `npm run build`
- verified the activation flow and `/channels` destination locally at
desktop and mobile widths
2026-08-03 08:29:22 -07:00
Ben Taylor 52966e6ec1 chore(examples): move the starters onto channels 0.6.1 (#6329)
## What

Bumps `@copilotkit/channels` from `0.6.0` to `0.6.1` in all 15
integration starters that host a Channel, with lockfiles regenerated to
match. Nothing else changes — `@copilotkit/*` stays on `1.65.0`.

`examples/slack` and `examples/teams` are untouched: they consume the
workspace copy (`workspace:*`), so they already track the fix.

## Why

`channels@0.6.1` carries exactly one change —
[#6322](https://github.com/CopilotKit/CopilotKit/pull/6322), where
`createChannel`'s clone check warns instead of throwing when `clone()`
drops subclass state. On `0.6.0`, a starter hosting a Channel through
`@ag-ui/langgraph` **refuses every turn**, because
`LangGraphAgent.clone()` leaves `emittedToolCallStartIds` and
`eventsStreamActive` behind — both per-run scratch that is
re-initialized before anything reads it. The starters are where that
failure is user-visible, so they shouldn't sit on the release that has
it.

## No runtime release needed

The question came up whether `@copilotkit/runtime` has to be re-released
so the pins don't conflict. It does not. The fix lives entirely in
`@copilotkit/channels-core`, and every path to it is a caret range:

| consumer | asks for | resolves to |
| --- | --- | --- |
| `@copilotkit/channels@0.6.1` (umbrella) | `channels-core` exactly
`0.6.1` | 0.6.1 |
| `@copilotkit/runtime@1.65.0` | `channels-core: ^0.6.0` | 0.6.1 |
| `@copilotkit/channels-intelligence@0.6.0` (runtime's one exact
channels pin) | `channels-core: ^0.6.0` | 0.6.1 |

The umbrella does not depend on `channels-intelligence`, so nothing
pulls a second copy of it in alongside the runtime. Everything dedupes
onto one `channels-core@0.6.1`, which is what makes the runtime's own
channel path pick up the fix without a release of its own.

## Testing

**1. Every regenerated lock resolves exactly one `channels-core`, at
0.6.1** — verified rather than reasoned, since a second nested copy is
the failure mode that would have forced a runtime release:

```
a2a-middleware: node_modules/@copilotkit/channels-core@0.6.1
adk: node_modules/@copilotkit/channels-core@0.6.1
claude-sdk-python: node_modules/@copilotkit/channels-core@0.6.1
agno: node_modules/@copilotkit/channels-core@0.6.1
claude-sdk-typescript: node_modules/@copilotkit/channels-core@0.6.1
langgraph-python: node_modules/@copilotkit/channels-core@0.6.1
crewai-flows: node_modules/@copilotkit/channels-core@0.6.1
langgraph-js: node_modules/@copilotkit/channels-core@0.6.1
mastra: node_modules/@copilotkit/channels-core@0.6.1
llamaindex: node_modules/@copilotkit/channels-core@0.6.1
ms-agent-framework-dotnet: node_modules/@copilotkit/channels-core@0.6.1
pydantic-ai: node_modules/@copilotkit/channels-core@0.6.1
mcp-apps: node_modules/@copilotkit/channels-core@0.6.1
ms-agent-framework-python: node_modules/@copilotkit/channels-core@0.6.1
strands-python: node_modules/@copilotkit/channels-core@0.6.1
```

**2. The full `@copilotkit/*` resolution in the reference starter
(`langgraph-python`)** — `channels-intelligence` correctly stays at
`0.6.0` (runtime's exact pin) while consuming the 0.6.1 core:

```
1.65.0 @copilotkit/a2ui-renderer     0.6.1 @copilotkit/channels
0.6.1  @copilotkit/channels-core     0.6.1 @copilotkit/channels-discord
0.6.0  @copilotkit/channels-intelligence
0.6.1  @copilotkit/channels-slack    0.6.1 @copilotkit/channels-teams
0.6.1  @copilotkit/channels-telegram 0.6.1 @copilotkit/channels-ui
0.6.1  @copilotkit/channels-whatsapp 1.65.0 @copilotkit/core
1.65.0 @copilotkit/react-core        1.65.0 @copilotkit/runtime
1.65.0 @copilotkit/shared            1.65.0 @copilotkit/web-components
```

**3. Reference starter installs and typechecks its channel host** — real
`npm install`, not lock-only:

```
> copilotkit-langgraph-template@0.1.0 typecheck:channel
> tsc -p tsconfig.channel.json --noEmit
EXIT=0

installed core: 0.6.1 | intelligence: 0.6.0
```

**4. The published 0.6.1 tarball actually carries the fix** — checked
the installed dist, not just the version number, so a mis-built release
would not pass as fixed:

```
node_modules/@copilotkit/channels-core/dist/create-channel.js
74:    warnOnCloneDroppedOwnFields(prototype, cloned);
132: function warnOnCloneDroppedOwnFields(prototype, cloned) {
139:    console.warn(`createChannel: ${name}.clone() dropped ${dropped.join(", ")}. ` +
```

`console.warn`, not `throw` — the 0.6.0 behaviour is gone.

**5. No unrelated dependency drifted.** Filtering every
non-`@copilotkit/channels*` line out of a regenerated lock diff leaves
nothing:

```
$ git diff examples/integrations/adk/package-lock.json | grep -E "^[+-]" \
    | grep -vE "integrity|resolved|@copilotkit/channels" | grep -E '"[a-z]' | sort | uniq -c
   8 +      "version": "0.6.1",
   8 -      "version": "0.6.0",
```

**Not tested:** no starter was run end-to-end against a live Channel
here — the change is a version pin, and the behaviour it unblocks was
verified in #6322.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-03 10:11:03 -05:00
renovate[bot] 26a23bbf3a chore(deps): update github actions (#6326)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [pnpm/action-setup](https://redirect.github.com/pnpm/action-setup) |
action | patch | `v6.0.9` → `v6.0.10` |
|
[zizmorcore/zizmor-action](https://redirect.github.com/zizmorcore/zizmor-action)
| action | patch | `v0.6.1` → `v0.6.2` |

---

### Release Notes

<details>
<summary>pnpm/action-setup (pnpm/action-setup)</summary>

###
[`v6.0.10`](https://redirect.github.com/pnpm/action-setup/compare/v6.0.9...v6.0.10)

[Compare
Source](https://redirect.github.com/pnpm/action-setup/compare/v6.0.9...v6.0.10)

</details>

<details>
<summary>zizmorcore/zizmor-action (zizmorcore/zizmor-action)</summary>

###
[`v0.6.2`](https://redirect.github.com/zizmorcore/zizmor-action/releases/tag/v0.6.2)

[Compare
Source](https://redirect.github.com/zizmorcore/zizmor-action/compare/v0.6.1...v0.6.2)

zizmor 1.29.0 is now the default version.

</details>

---

### Configuration

📅 **Schedule**: (in timezone America/Los_Angeles)

- Branch creation
  - "before 9am every weekday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/CopilotKit/CopilotKit).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->
2026-08-03 15:03:29 +00:00
Sam Julien 9c250af1a9 Merge remote-tracking branch 'origin/main' into codex/channels-docs-followups
# Conflicts:
#	showcase/shell-docs/src/lib/__tests__/channels-docs.test.ts
2026-08-03 08:01:08 -07:00
Benjamin Taylor 23671e09f1 chore(examples): move the starters onto channels 0.6.1
0.6.1 carries one change: createChannel's clone check now warns instead of
throwing when `clone()` drops subclass state (#6322). On 0.6.0 a starter
hosting a Channel through @ag-ui/langgraph refuses every turn, because
LangGraphAgent's clone() leaves `emittedToolCallStartIds` and
`eventsStreamActive` behind -- both per-run scratch that is re-initialized
before anything reads it, so dropping them was never the problem. The
starters are the surface where that failure is user-visible, so they should
not sit on the release that has it.

No @copilotkit/* bump rides along, and none is needed. The fix lives entirely
in @copilotkit/channels-core, and every path to it is a caret range:
runtime@1.65.0 asks for channels-core ^0.6.0, and channels-intelligence@0.6.0
(which runtime does pin exactly) asks for ^0.6.0 as well. Both resolve onto
the same 0.6.1, so the runtime's channel path picks up the fix without a new
runtime release. Verified from the regenerated locks rather than assumed:
each of the 15 resolves exactly one channels-core, at 0.6.1, with no second
copy nested under runtime.

Lockfiles were regenerated with --package-lock-only; the diffs contain
@copilotkit/channels* lines and nothing else, so no unrelated dependency
floated forward in the process.
2026-08-03 09:19:47 -05:00
renovate[bot] 42e0df471a chore(deps): update github actions 2026-08-03 14:10:54 +00:00
Ben Taylor d6f3914d18 chore: release channels v0.6.1 (#6328)
## Release channels v0.6.1

**Scope:** `channels` | **Bump:** `patch`

---

### How this release process works

1. **This PR was created automatically** by the "release / create-pr"
workflow.
   It bumped the `channels` packages to `0.6.1`
   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 `channels` packages to npm at version `0.6.1`
   - Creates git tag `channels/v0.6.1`
   - 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.
channels/v0.6.1
2026-08-03 09:08:49 -05:00
BenTaylorDev bdf054f8bd chore: release channels v0.6.1 2026-08-03 14:06:07 +00:00
Ben Taylor b0848f522f fix(channels): report a clone that drops subclass state, do not refuse the turn (#6322)
A Channel built with `LangGraphAgent` cannot answer a single message
today. `isolateAgentInstance` throws when an agent's `clone()` does not
carry the subclass' own fields, and `LangGraphAgent.clone()` drops
`emittedToolCallStartIds` and `eventsStreamActive` — so every turn is
refused before the agent runs.

## Why refusing was the wrong call

Whether a dropped field matters depends on what it **holds**, and the
check cannot see that:

- **Config** read during the run and never rewritten (an auth client, a
URL) genuinely guts the agent when lost.
- **Per-run scratch state** is re-initialized at the start of every run,
so losing it changes nothing. `LangGraphAgent`'s two fields are exactly
this — both are reset when a run binds its subscriber, before anything
reads them.

The tell is that the identical clone happens on **every ordinary runtime
request** (`agent-utils.ts` clones per request, SSE and Intelligence
alike) and has never caused a problem. Channels differed only in
asserting at clone time, before the run that would have repopulated the
fields.

## Verified against a real Slack round trip

With the throw downgraded locally, the same Channel that could not take
a turn ran the agent and replied in Slack — inbound delivery, agent
execution, and egress all working. The only thing that had changed was
this check.

## What it does now

Warns, naming the dropped fields and both readings, and continues. The
check still earns its place: `A2AMiddlewareAgent`'s base `clone()` drops
`orchestrationAgent`, `agentClients` and `agentCards`, which **are**
config, and that is worth seeing.

I checked every agent class the starters build, by instantiating each
and diffing own keys against its clone:

| Class | Result |
| --- | --- |
| `HttpAgent`, `LlamaIndexAgent`, `BuiltInAgent`, `MastraAgent` | clean
|
| `LangGraphAgent` | drops `emittedToolCallStartIds`,
`eventsStreamActive` (per-run scratch) |
| `A2AMiddlewareAgent` (base) | drops `orchestrationAgent`,
`agentClients`, `agentCards`, `instructions` (config) |

## Deliberately not done

Copying the dropped fields onto the clone. That shares one mutable
object across concurrent turns — the exact hazard this isolation exists
to prevent.

## Follow-up

The real fix belongs in `@ag-ui/langgraph`, whose `clone()` should carry
those fields. Tracked separately; this unblocks the release in the
meantime.

## Tests

`nx test @copilotkit/channels-core` — 38 files / 257 tests, including a
rewritten case asserting the warn-and-continue contract and a new one
asserting every dropped field is named once per turn. `tsc --noEmit`
clean.

Note: `@copilotkit/channels-intelligence:test` fails in my checkout with
unresolved `rxjs` / `@copilotkit/channels-slack/render` — identical
failures with this change stashed, so it is a local workspace install
issue, not this PR.
2026-08-03 06:34:12 -05:00