mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
angular/v0.3.1
14123 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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 | ||
|
|
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 | ||
|
|
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. |
||
|
|
979a8ee990 | feat(channels-slack): support data visualization blocks | ||
|
|
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. |
||
|
|
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. |
||
|
|
8101e5ef52 |
feat(skills): make managed Intelligence the default setup path, add a Channels skill (refs OSS-705) (#6298)
Companion to CopilotKit/Intelligence#714 (OSS-705). That PR builds the `copilotkit channels` CLI; this one covers the skills and docs half of the same [PRD](https://app.notion.com/p/3af3aa381852810b8254ec0cbb5be6af). ## Managed Intelligence becomes the default path in `copilotkit-setup` The most-used "add CopilotKit to your project" path walked every new user into the self-hosted SSE runtime and never offered the managed one. `CopilotIntelligenceRuntime`, `CopilotKitIntelligence`, the required `identifyUser`, and the hosted environment values all appeared in this skill's *reference* files but were wired by **no step** — so the skill could describe managed Intelligence without ever producing it. - **Step 2 now chooses the runtime mode before any runtime code is written**, because the mode changes how the runtime is constructed and retrofitting it means rewriting the file. Managed is the recommended default and has real wiring. - **Self-hosted SSE stays fully documented** as a deliberate opt-out, with its prerequisites and its tradeoff stated at the point of choice. The OSS packages are published and MIT-licensed, so obscuring the alternative would not prevent its use and would cost credibility on everything around it. - **Step 6 becomes the actual Intelligence step** rather than a telemetry aside, and separates the two credentials that setup mistakes conflate: the server-side project API key (a secret, and never `NEXT_PUBLIC_`-prefixed) and the public license key (a project identifier meant to reach the client). - **Fixes a command that does not exist.** Both the skill and `references/telemetry-setup.md` instructed `npx copilotkit auth`. The command is `login`, and `project select` is what provisions the project. ## New `copilotkit-channels` skill Covers the code half: the Channel declaration, the long-running host requirement, and which mounts start activation on their own versus which wait for an explicit `channels.ready()`. It leads with the managed-versus-self-hosted boundary, because both product families use the words "channels" and "Slack" and the OSS demos ship their own Slack manifest and Teams package. ## Docs - `channels/intelligence.mdx` — the CLI as a **peer** path to the wizard, with the tradeoff stated. The wizard walkthrough is untouched, and the docs say explicitly that either path can finish what the other started. - `packages/channels-{slack,teams}/README.md` — directional pointers: lead with what managed provides, route there, state plainly that the self-hosted adapter remains supported. ## Two deviations from the PRD, both deliberate 1. **Pointers are scoped to Slack and Teams.** The PRD asks for all eight `packages/channels-*/README.md`. Managed Channels supports only those two providers, so the same pointer in `channels-discord`, `-telegram`, or `-whatsapp` would route a reader to something that cannot serve them. 2. **`frontends/{slack,teams}.mdx` need no pointer.** The PRD lists them as describing the OSS adapter product; both already document the *managed* path ("CopilotKit Intelligence holds the Slack credentials") and both already link to the configuration page, which now offers the CLI. ## A correction worth reviewing The Channels skill first asserted that activation is lazy on every host and that `await listener.channels.ready()` is always required — wrong, and wrong in its own Step 4 example, which uses `createCopilotNodeListener`. OSS-641 split the behavior: node and express start activation at creation; hono and the generic fetch handler still defer. The skill now carries the table and says to check the mount, because telling a Node host to add a call it does not need is as unhelpful as omitting one that is required. `showcase/.../deploy-and-operate.mdx` already described this correctly and is unchanged. ## Notes for review - A standalone skill **must** be registered in `RESERVED_LIFECYCLE_SLUGS` (`scripts/sync-plugin-skills.ts`) or `pnpm sync:plugin-skills` deletes it as an orphan. Registered, and the test now pins that requirement with the reason. - `pnpm check:plugin-skills` passes; `scripts/__tests__/sync-plugin-skills.test.ts` passes (50 files / 483 tests). - The last commit used `--no-verify`, disclosed in its message: touching `packages/*/README.md` makes 13 projects affected and the pre-commit hook aborts that run with `exit 130`. The same target set (`test`, `publint`, `attw` for `@copilotkit/channels-intelligence`) passes standalone. That commit is two markdown files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
a97abd2bc5 |
feat(examples): let every starter host a managed Channel (#6315)
## What this does
Every CopilotKit starter can now host an Intelligence Channel
(Slack/Teams) as well as a web app, so `copilotkit init`'s channel path
can finish at `npm run channel` instead of asking the developer to
hand-wire runtime source afterwards.
Per starter, four files:
1. **`agent.ts`** — agent construction moves out of the Next.js runtime
route into a `createDefaultAgent()` factory. Pure extraction; the web
mount's behaviour is unchanged.
2. **`route.ts`** — imports the factory instead of constructing inline.
3. **`channels.mts`** — declares the Channel: name resolution,
`createChannel`, and the `onMessage` handler. This is the file a
developer edits to *customise* a Channel — commands, reactions, an
`onMention` handler. It holds the only per-starter difference in the
pair: the agent import path (`./src/agent` or `./app/agent`).
4. **`channel-host.mts`** — the process that owns the Channel's
lifetime. **Byte-identical in all 15 starters**, so the CLI can emit it
verbatim.
The host declares **no adapters, no provider credentials, and no
provider endpoint** — Intelligence owns the provider edge — which is why
one file works for every provider. Adding WhatsApp/Telegram/Discord
later touches the server and the CLI, never a starter.
The host also runs **no HTTP server**. Nothing calls this process: the
gateway connection is outbound, and holding it open is what keeps the
process alive. It uses `createCopilotRuntimeHandler` + `ready()` — the
long-running-host pattern documented in `fetch-handler.ts` — rather than
building a request listener for its activation side effect.
Covers 15 starters (17 of 21 CLI frameworks; `langgraph-python` backs
three). `langgraph-fastapi` gets dependency pins only, because it is
enrolled in the `_parity` drift check and would otherwise mismatch the
north-star.
## ⚠️ Temporary, must not ship to users as-is
- **All `@copilotkit/*` deps are pinned to a prerelease**,
`1.64.3-canary.1785633429`. Stable `1.64.2` lacks `identifyUser` on
`createChannel`, so tracking `main` required the canary. **These pins
must move to a stable release before the CLI's channel path goes live.**
- **`mastra` carries an `.npmrc` with `legacy-peer-deps=true`.**
`@ag-ui/mastra` declares a peer of `@copilotkit/runtime@^1.10.5`, and
node-semver excludes prereleases from a caret range — so *any*
prerelease pin fails that check, and a fresh clone would fail `npm
install` without it. The real fix is a prerelease-inclusive peer range
upstream (its other peers already use `>=1.0.0-0 <2.0.0-0`).
## Review feedback addressed
**"This file seems overly complex and adds a brand new service alongside
an already existing webserver"**
([thread](https://github.com/CopilotKit/CopilotKit/pull/6315#discussion_r3699832425)).
The complexity was real and is fixed in two ways below. Folding the
Channel into the existing Next.js route is not possible: activation on
the App Router path is lazy by design (`fetch-handler.ts:39`,
`hono.ts:15-26`), so `channels: [channel]` in `route.ts` would build a
ChannelManager, open no socket, and **silently never connect**; forcing
it with `ready()` mints a competing listener per cold start. A Channel
is a long-running worker, not a serverless request handler. Full
reasoning in the thread.
What did change:
- **The Channel moved out of the host** into `channels.mts`, which also
made the host byte-identical everywhere.
- **The HTTP server is gone.** Its comment claimed the server was what
"keeps the lifecycle-owning process alive." That is false — an open
undici WebSocket holds the event loop on its own. The server was
therefore standing up a second, uncalled copy of the runtime API on port
8300 for no reason. Removing it also drops `node:http`, `basePath`, and
the `CHANNEL_PORT` env var.
Terminology: these are **Channels**, not "managed Channels", throughout
the starter READMEs, host comments, and log output. "Managed" stays in
the docs and runtime, where it is the load-bearing discriminator against
direct adapters.
Still open, tracked as a fast-follow: **OSS-729** —
`resolveChannelName()` is ~56 hand-rolled lines per starter reading
`.copilotkit/channels.json`, a file that already has a versioned zod
schema and a canonical parser in `Intelligence/libs/channels-setup`.
That library is unpublished, so every consumer re-derives the read and
ignores `version` while doing so. Publishing a read-side
`resolveDeclaredChannel()` helper collapses those 56 lines to about
three.
## Verification
- **14/14** starters with a `typecheck:channel` script pass. `mastra`
has no such script by design (
|
||
|
|
768a69c99d |
fix(channels): report a clone that drops subclass state, do not refuse the turn
isolateAgentInstance threw when an agent's clone() did not carry the subclass's own fields. That rejected every turn on a Channel built with LangGraphAgent -- its clone() drops emittedToolCallStartIds and eventsStreamActive -- so the reference starter could not answer a single message. The refusal was wrong because 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) does gut the agent when it is 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 for 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. Confirmed against a real Slack round trip: with the throw downgraded, the same Channel that could not take a turn ran the agent and replied. So it warns and continues, naming the fields and both readings. The check still earns its place: A2AMiddlewareAgent's base clone() drops orchestrationAgent, agentClients and agentCards, which are config, and that is worth seeing. Deliberately not done: copying the dropped fields onto the clone. That shares one mutable object across concurrent turns, the exact hazard the isolation exists to prevent. Upstream fix to follow in @ag-ui/langgraph, whose clone() should carry them. |
||
|
|
475002e49d |
chore(examples): move the starters off the canary onto stable
The canary pin existed for one reason: createChannel's identifyUser was absent from stable, and the pin carried a note that it must not reach users as-is. Stable has caught up -- @copilotkit/* 1.65.0 and @copilotkit/channels 0.6.0 -- so the workaround goes. This is not only hygiene. The runtime validates each delivery with an exact field set, so a client and a server that disagree fail in BOTH directions: a client expecting a field the server omits, and equally a client receiving one it does not expect. Now that every Intelligence environment sends the prepared turn's messageRef, pinning back to an older stable would break exactly as hard as staying on a canary would have before. 0.6.0 expects it, which is what makes it the correct pin rather than merely a newer one. Verified before committing: channels-intelligence@0.6.0 requires messageRef on a text turn, channels-core@0.6.0 carries identifyUser, and channels@0.6.0 pins its subpackages exactly rather than by range, so there is no internal skew. The reference starter installs, typechecks its channel host, and builds. Its one remaining tsc error is a pre-existing recharts type mismatch, untouched here. langgraph-fastapi is included: it does not ship a host, but this branch pinned it to the canary, so it cannot be left there. |
||
|
|
bd2b2a7a9c |
chore: release monorepo v1.65.0 (#6318)
## Release monorepo v1.65.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.65.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.65.0` - Creates git tag `monorepo/v1.65.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.65.0 |
||
|
|
dab3cde9a0 | docs(channels): document Teams one-command setup | ||
|
|
6988d5d8e2 | chore: release monorepo v1.65.0 | ||
|
|
bba3706bdc |
chore: release channels v0.6.0 (#6317)
## Release channels v0.6.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.6.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.6.0` - Creates git tag `channels/v0.6.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.6.0 |
||
|
|
b2803f89f9 |
docs(channels): name the failure where a Channel is online and still silent
The troubleshooting list only covers a Channel that never connected. When the host
logs that the Channel IS online and the bot still says nothing, every item on it
comes back correct and the reader is stuck -- while the skill's headline failure
description ("serves HTTP, reports no error, answers nothing") matches the symptom
exactly and points at the one cause that is already ruled out.
That case is a version disagreement between the installed @copilotkit/channels-*
packages and the Intelligence serving them. The runtime validates each delivery
strictly rather than as a loose subset, so a client expecting a field its server
does not send fails every turn of that kind at the join boundary, before any
handler runs. Nothing is posted back to the provider from there, which is why it
reads as silence rather than an error.
Names the log line to look for, says the category is all the signal there is
because the message itself is not logged, and gives the two directions the skew
comes from -- a prerelease client ahead of hosted Intelligence, or a self-hosted
deployment behind its client.
Found the hard way: this cost an afternoon of log archaeology that the skill, as
written, would have sent in the wrong direction.
|
||
|
|
63c15ce445 | chore: release channels v0.6.0 | ||
|
|
d00831878b |
docs(channels): lead with the scaffolded Channel, keep hand-wiring as the appendix
The starters now ship the Channel and its host, so the skill's spine -- install, declare, pass to the runtime, mount a host -- describes work a scaffolded project has already done. An agent following it there would add a SECOND createChannel beside the one in channels.mts, and since the host resolves exactly one Channel name and refuses to start when several are declared, that does not produce a second bot: it produces a project that will not boot. So the skill now opens by deciding which path you are on, on one observable fact (is there a channel-host.mts), and leads with customisation: which of the three scaffolded files is yours to change, how to add an onMention or onReaction beside the onMessage that ships, and why per-provider tools are omitted rather than forgotten. Hand-wiring is unchanged and complete, moved behind a heading that says what it is. It stays because "scaffold-first" is not "scaffold-only" -- a project that predates the Channel still needs it, and the CLI still points there when it finds no host. Two corrections while restructuring. onCommand is now called out as absent on purpose: managed Slack is events-only, so a registered slash command is a handler nothing will ever call. And a separate host needs no HTTP server at all -- the gateway connection is outbound and holding it open is what keeps the process alive, which is what the shipped host actually does. The docs page listed two ways to configure a Channel and omitted the one that will carry the most volume: `copilotkit init` now leads an interactive developer all the way through provider setup and scaffolds the host, so it leads that list. |
||
|
|
e1f88ebc12 |
refactor(examples): split the Channel out of the host, drop its HTTP server
Addresses review feedback that channel-host.mts is doing too much.
Two changes, both scoped to the starters:
1. Channel construction moves to a new `channels.mts` beside `agent.ts` —
name resolution, `createChannel`, and the `onMessage` handler. That is
also the file to edit to customise a Channel (commands, reactions,
onMention), which previously meant editing the host.
The per-framework agent import moves with it, so `channel-host.mts` is now
byte-identical in all 15 starters rather than 13 + 2.
2. The host no longer stands up an HTTP server. Its comment claimed the
server was what "keeps the lifecycle-owning process alive"; that is false.
An open undici WebSocket holds the event loop on its own — verified with a
standalone repro where a process with no HTTP server and no timers of its
own stayed up indefinitely on a single WebSocket connection. The server was
therefore serving a second, uncalled copy of the runtime API on port 8300
for no reason.
With the server gone, `createCopilotNodeListener` was the wrong factory —
it builds a request listener purely for its activation side effect. The
host now uses `createCopilotRuntimeHandler` + `ready()`, which is the
documented long-running-host pattern (see fetch-handler.ts). This also
drops `node:http`, `basePath`, and the CHANNEL_PORT env var.
Behaviour is unchanged: same Channel, same agent, same status reporting, and
the same non-zero exit on activation failure.
Verified: 14/14 starters with a `typecheck:channel` script pass; mastra has no
such script by design (
|