mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
docs/showcase-sdk-reference-20260805
14241 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3a46947ffe | fix(runtime): wait for joined event channel | ||
|
|
84acddf5b1 | feat(runtime): batch durable runner events | ||
|
|
73286b591f | fix(runtime): keep accepted runs alive during reconnect | ||
|
|
5cc22a5a1f | fix(runtime): preserve gateway handoff continuity | ||
|
|
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 |
||
|
|
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`. |
||
|
|
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 |
||
|
|
bc968ce96b | chore: release angular v0.3.1 | ||
|
|
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
|
||
|
|
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 |
||
|
|
a87b77a991 | chore: release monorepo v1.66.0 | ||
|
|
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 |
||
|
|
53bf978904 | chore: release channels v0.7.0 | ||
|
|
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. |
||
|
|
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. |
||
|
|
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`. |
||
|
|
2cc279b4e9 | test(channels): tolerate wrapped setup copy | ||
|
|
9ca0727a08 | docs(channels): refine launch guidance | ||
|
|
9910ac9293 | docs(channels): reconcile launch documentation | ||
|
|
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. |
||
|
|
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 |
||
|
|
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. |
||
|
|
00f16379c9 | style: auto-fix formatting | ||
|
|
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. |
||
|
|
979a8ee990 | feat(channels-slack): support data visualization blocks | ||
|
|
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. |
||
|
|
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. |
||
|
|
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.
|
||
|
|
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. |
||
|
|
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. |
||
|
|
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` |
||
|
|
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. |
||
|
|
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 |
||
|
|
65150a683b | fix(channels-intelligence): repair all transcript consumers | ||
|
|
b88f9b7e4f | feat(channels): complete native JSX contracts | ||
|
|
f8145b05b7 | feat(channels): add native Slack and Teams JSX | ||
|
|
fa92ebcf44 | feat(channels): recover actions by stable JSX key | ||
|
|
8707d8ce12 | feat(channels): add agent-rendered component tools | ||
|
|
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) |
||
|
|
6c2c289d85 | fix(channels-intelligence): restore prepared trigger files | ||
|
|
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. |
||
|
|
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 |
||
|
|
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) |
||
|
|
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=--> |
||
|
|
9c250af1a9 |
Merge remote-tracking branch 'origin/main' into codex/channels-docs-followups
# Conflicts: # showcase/shell-docs/src/lib/__tests__/channels-docs.test.ts |
||
|
|
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. |
||
|
|
42e0df471a | chore(deps): update github actions | ||
|
|
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 |
||
|
|
bdf054f8bd | chore: release channels v0.6.1 | ||
|
|
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. |