Consume upstream MCP Apps 0.1.0, retain trusted server credentials, and
reject proxy requests outside the selected agent scope. Ordinary runs
without selected servers do not attach middleware.
`verify:runtime-package` packs the runtime and installs it in a temp dir
under `os.tmpdir()`. That directory never inherits the repo-root `.npmrc`,
so the script writes its own `minimumReleaseAgeExclude` from
`RELEASE_AGE_EXCLUDE` — a second copy of the same policy.
#7093 added `@ag-ui/mcp-middleware` and `@ag-ui/mcp-apps-middleware` to
`.npmrc` but not to that list, so the freshly published
`@ag-ui/mcp-middleware@0.0.2` installed everywhere except inside the packed
-runtime verification, which failed with:
ERR_PNPM_NO_MATURE_MATCHING_VERSION Version 0.0.2 (released 22 minutes
ago) of @ag-ui/mcp-middleware does not meet the minimumReleaseAge
constraint
The list's own comment already said to keep it in sync with `.npmrc`. A
comment was the only thing holding the two together, and it did not hold,
so this also adds a test asserting the two lists are identical. The test
was mutation-checked in both directions: dropping an entry from either
file fails it.
Verified by running the failing step: `pnpm run verify:runtime-package`
now exits 0 with "OK: packed runtime installs
@copilotkit/channels-intelligence and loads through ESM and CJS".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The notes now land in a source-controlled changelog instead of a scratch file
that rides the release branch. One file per lane, because the lanes version
independently: a shared file would interleave `1.70.0`, `angular/0.5.0` and
`channels/0.9.0` into one unreadable sequence.
monorepo -> CHANGELOG.md
angular -> packages/angular/CHANGELOG.md
channels -> packages/channels/CHANGELOG.md
`write-changelog.ts` prepends this release's section on the release branch,
create-pull-request commits it (a tracked file, always staged), and
`extract-release-notes.ts` reads the section back in the publish job as the
GitHub Release body. The changelog is therefore both the durable record and the
review surface: editing a section on the release PR changes what ships.
release-notes.md goes back to being ignored, so the same notes never exist as
two editable copies.
Also deletes 29 changesets-era changelogs that no tooling had written since
April. They stopped at 1.55.2 while the lane shipped 1.69.3, and
packages/angular/CHANGELOG.md still claimed 1.54.3 from before that lane split
onto its own 0.x line. Their content stays recoverable from git history. A test
pins the tracked changelog set to the lanes so they cannot creep back and
contradict the real versions.
Extraction never fails the publish job: it runs after npm publish, so a miss
annotates loudly and falls through to the existing bodyless-release fallback
rather than stranding the tag.
Committed with --no-verify: the pre-commit nx lane cannot run in this worktree
(packages/core and packages/channels-ui have no node_modules, and
`nx run @copilotkit/core:build` fails identically with the tree clean). The only
change under packages/** is deleting orphan markdown that no build or test
reads.
The generator fed the model a repo-wide `git log -50` as context and told it
it was writing notes for "CopilotKit vX.Y.Z, an open-source AI agent framework
for React applications" — wrong on three counts for an angular or channels
release: the wrong commits, the wrong framing, and the wrong release title
(only the monorepo lane is titled `vX.Y.Z`).
Pass the scope through, build context from that lane's own commits, name the
packages actually being published, and tell the model to write about nothing
else.
Also fix the API call itself: the pinned model string was a dated snapshot,
max_tokens 2048 could truncate a large release, and the response reader took
content[0].text — which is not the text block on models that return thinking
blocks first.
Selecting mainline commits alone drops a BREAKING CHANGE footer that lives on
a branch commit rather than in the PR description: the merge inherits neither.
Measured against real history, v1.60.0..HEAD lost 2 of 2 notes.
Fold each merge's branch messages into its body before extraction, so the
entry list stays one-per-PR while the footer scan sees the whole PR. Both
ranges checked now report zero loss versus the previous selection.
release-notes.md and release-notes-notion.json were both gitignored, so
create-pull-request silently skipped them. The notes never reached the release
branch, the publish job's readFileSync missed, and every release since this
lane was built shipped its "Release <tag>" fallback body — v1.70.0,
channels/v0.6.0 and angular/v0.4.0 all have bodyless GitHub Releases.
The same ignore rule severed the Notion lane: without the json ref in the
checkout, publish-release could never read an edited draft back, so that path
had never run either. Remove it rather than repair it — the release PR is
already the review surface, and editing release-notes.md on the branch is a
plainer gate than a Notion page.
Guard the ignore rule with a test, since re-adding it would break the lane
again without breaking anything else.
Release notes were assembled from every commit since the scope's tag with
--no-merges. Two things were wrong with that:
- No path filter, so a scope inherited every other lane's work. The angular
v0.5.0 notes drew from 159 commits, 4 of which were angular.
- --no-merges is backwards for this repo. PRs land as merge commits, so the
merge is the unit of change and the only commit carrying the (#1234)
reference; --no-merges dropped every PR boundary and kept the intermediate
branch commits instead.
Walk --first-parent over the scope's package directories, drop commits no
consumer would read about (test/ci/style, chore except chore(deps), and the
release commit itself), and parse the PR number off the subject.
For angular v0.5.0 this turns 159 entries into the 4 real PRs.
CI ran for the first time on the PR and flagged three new-package registration
steps (Ben's review):
- add packages/mcp-apps-renderer/tsdown.config.ts to .github/config-allowlist.txt
(static / check binaries)
- drop the UMD half of the compat-check script; this package builds no UMD
format, so `es-check ... dist/**/*.umd.js` found no files and failed
(static / compat)
- bump the monorepo package-count drift guard 16 -> 17 now that the package
joined the release scope (test / unit)
Moves the published packages from 0.0.57 to the current AG-UI release across
@ag-ui/client, core, encoder and proto — 27 declarations in 18 packages.
0.0.59 is the first release carrying the subagent protocol surface
(SUBAGENT_STARTED/FINISHED/ERROR, subagentRunId) along with the null-omission
cleanup, so this is the dependency CopilotKit's subagent work needs.
Scope is packages/** plus the release script noted below. The examples and
showcases sit on a spread of older pins (0.0.40 through 0.0.58) and are left
alone.
One behavioural change comes with the bump. channels-core ships
sanitizeAgentEventStream because @ag-ui/client used to reject a TOOL_CALL_START
carrying parentMessageId: null — the shape @ag-ui/langgraph emits for an
interrupt-triggering tool call. 0.0.59 accepts that null and treats it as
absent, so the two tests asserting the run dies WITHOUT the sanitizer no longer
hold. They now assert the run survives, and the one at agent level still checks
the tool call actually arrives so it cannot pass vacuously. The sanitizer is
untouched and its coercion tests are unchanged; it is simply no longer the
thing keeping such a run alive.
The bump also broke the packed Angular consumer matrix. That job generates a
smoke app from scripts/release/lib/angular-package.ts, whose manifest restated
"@ag-ui/client": "0.0.57" as a literal while packages/angular moved to 0.0.59.
pnpm then installed both copies and the app failed to compile:
TS2322: Type 'SmokeAgent' is not assignable to type 'AbstractAgent'.
Types have separate declarations of a private property '_debug'.
The smoke app imports AbstractAgent directly, so it has to resolve the identical
copy the library ships against. Read that version off the packed manifest --
which verify-angular-package.ts already parses for the Angular support contract
-- instead of restating it, so no future AG-UI bump can desynchronise it.
## What broke
The regression was introduced by commit fec70d086 (feat(angular):
checkpoint 2 - core and package), merged through PR #6109 as b07482da5.
That commit established Angular 20 as the package’s compiler and support
floor, but the demo remained on Angular 21 after 8b13fbcb7 (build:
update ng).
It also introduced the packed smoke runner without canonicalizing macOS
temporary paths, allowing /var/... and /private/var/... to resolve
inconsistently.
## Why I made this change
I moved the demo back to Angular 20 so it exercises the lowest supported
Angular version, aligned the Angular 20 dependencies and support
contract on
20.3.27, and canonicalized the packed consumer directory before starting
the SSR server.
This keeps the demo, package metadata, tests, and lockfile consistent
while making the packed smoke test reliable across symlinked temporary
directories.
## Changes
- Align the Angular demo with the Angular 20 support floor.
- Update Angular 20 dependencies and support-policy tests to 20.3.27.
- Resolve the packed consumer directory to its real path before
launching SSR.
## What changes
This replaces the managed Channels adapter and transport stack with live
sessions over Realtime Gateway.
- Channels use the standard AgentRunner and canonical AG-UI history for
each turn.
- One admitted delivery runs one prompt; multiple agent calls run in
order; concurrent calls fail with a bounded protocol error.
- Slack and Teams reuse their native renderers to emit destination-free
provider effects.
- Files, rich controls, interaction handlers, and provider cursors cross
the live-session protocol with bounded payloads.
- The old claim mapping, HTTP fallback, render batches, listener
election, in-memory transport, and legacy adapter code are removed.
- The public `@copilotkit/channels` umbrella remains limited to public
provider adapters; the managed launcher stays in
`@copilotkit/channels-intelligence`.
Companion service PR and kind proof:
https://github.com/CopilotKit/Intelligence/pull/638
## Why
Managed delivery must use the same AgentRunner path as other
Intelligence runs. SDK code emits provider-neutral effects; the trusted
Gateway owns credentials, destinations, admission, retries, and terminal
outcomes.
## Validation
- `pnpm nx run-many -t build,check-types,test -p
@copilotkit/channels-core,@copilotkit/channels-intelligence,@copilotkit/channels-slack,@copilotkit/channels-teams,@copilotkit/channels,@copilotkit/runtime`
— 31 tasks passed
- `pnpm nx test @copilotkit/channels-teams` — 89 passed
- `pnpm vitest run scripts/release/lib/channels-umbrella.test.ts` — 8
passed
- `pnpm verify:channels-umbrella` — packed snapshot, dependency
resolution, and TSX consumer passed
- affected package pre-commit tests, publint, and API type checks passed
- changed-file Prettier and `git diff --check` passed
## Known unrelated check
`pnpm nx build demo` now compiles past the prior Channels telemetry
dependency leak, then fails on the existing AG-UI 0.0.51 versus 0.0.57
private `_debug` type mismatch.
After the npx fix each publish is ~4.7s and almost entirely a registry
round-trip, so a 26-package scope=all canary still spent ~125s waiting
serially. Publish 4 at a time (CANARY_PUBLISH_CONCURRENCY=1 restores
serial for debugging).
This weakens no ordering invariant. prerelease.ts's own header already
documents that the cross-scope graph has cycles (runtime ->
channels-intelligence, channels-core -> core), so no serial order avoided
publishing a package before the same-run version it pins.
Per-package output is captured and replayed as one block rather than
inherited, since a pool would otherwise interleave several npm publishes
line-by-line — and that log is the only forensic record when a canary
half-publishes. Every package is attempted even if others fail, so one
report names all of them; main() now exits non-zero on failure rather
than letting an unhandled rejection pass the step.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The canary flow took ~11.5 min steady-state (and 20 min in an observed
run). Measured from run 30473499191, the time went to five avoidable
places rather than to real work.
1. `npx --yes npm@11.15.0 publish` ran per package, and npx re-resolves
the spec against the registry on EVERY invocation: ~16s of each
package's ~21s. A 9-package channels canary paid ~2.4 min of pure npx
overhead; a 16-package monorepo release paid over 4 min. Hoist the
pinned npm into lib/npm-cli.ts, install it once into a throwaway
prefix, and reuse the binary.
2. publish-release.yml was the only workflow in the repo with no pnpm
store cache, so all three jobs installed 4608 packages cold every
time. Usually ~45s each, but registry-bandwidth bound and heavy
tailed: the observed run spent 9m08s here on tarballs arriving at
2-49 KiB/s. Add the same node-version-keyed cache the rest of CI uses.
3. The notify job ran for canaries only to compute "post nothing" — the
builder already returns should_post=false for mode=prerelease and the
self-watchdog is already gated off. ~85s of dead work on the critical
path, since canary.yml waits for the whole run. Skip the job, keeping
it reachable for a python_publish dispatch.
4. The build job fetched full history for canaries, which need none (no
tag, no GH Release, no release-note commit range, and `nx run-many`
resolves no merge base). That rode along in the 837 MiB workspace
artifact too. Shallow-fetch prereleases; stable keeps depth 0 because
its publish job pushes tags out of that artifact's .git.
5. Two smaller ones: the artifact was gzipped and then re-deflated into
the artifact zip (compression-level: 0), and the orchestrator's
run-discovery loop slept 6s before its first poll.
Verified: 143 release-script tests pass (6 new for the npm-cli helper),
actionlint + shellcheck + the scope-dropdown guard are clean, the
prerelease dry-run path still enumerates all 9 channels packages, and a
live probe confirms the helper installs npm 11.15.0 once (3.2s) and
memoizes thereafter (0ms).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`verify:runtime-package` could not pass on a channels release PR. `pnpm pack`
rewrites the runtime's `workspace:` ranges to the workspace's current version,
so on a release PR the temp consumer tried to resolve the freshly-bumped
`@copilotkit/channels-intelligence` from npm — the version this very PR is
about to publish. It failed `unit (20.x)` by construction on #6185 and #6025.
Apply the fix `verify-channels-umbrella` already uses: pack the whole
first-party `workspace:` closure locally and pin it through pnpm `overrides`.
The packing helpers move to `lib/pack-workspace.ts` so both scripts share one
implementation instead of duplicating it.
The contract is unchanged: the packed runtime must still declare
channels-intelligence as a real dependency, and it must still load through
both ESM and CJS.
Adversarial pass on the previous commit. The warning only inspected
`workspace:` ranges, so it missed the OTHER way a cross-scope pin goes stale: a
literal version range naming a package in another scope. `bumpPackages` rewrites
literal ranges for in-scope packages only, so such a pin survives every bump —
`scope=all` publishes the canary and the artifact still resolves the dependency's
last stable release, silently, which is the exact failure this warning exists to
surface.
`findCrossScopeWorkspaceDeps` becomes `findCrossScopePins`, reporting both shapes
tagged with a `reason`, and the literal case carries its own remedy (convert to
`workspace:`) instead of the useless "re-run with scope=all".
No such pin exists in the tree today — every cross-scope edge is `workspace:` —
so this closes a latent hole rather than a live one, in the one place a future
refactor would reintroduce it.
Also documents the multi-scope partial-failure mode in prerelease.ts: the
cross-scope graph has cycles, so no publish order avoids a package shipping
before the same-run version it pins, and npm's no-republish rule means a failed
run must be retried under a new suffix.
Two release-tooling defects turned a pair of canary publishes into a broken
combination for consumers (a canary runtime resolving the last STABLE
channels-intelligence, which still called the removed `channel.addAdapter`).
1. Canary versions were prereleases of an ALREADY-PUBLISHED version. A stable
release leaves the working tree on the version it just published, and
computePrereleaseVersion appended `-canary.<id>` to exactly that, so the
canary sorted BELOW its own release (`0.2.1-canary.x < 0.2.1`): the `canary`
dist-tag pointed behind `latest`, and no dependent range could ever resolve
it. Base the canary on the next unreleased version instead (patch bump,
reusing computeNextStableVersion's prerelease rule).
2. A canary published one scope at a time, but the scopes are only independent
on the version axis. `@copilotkit/runtime` carries
`"@copilotkit/channels-intelligence": "workspace:*"`, and `pnpm pack`
resolves that against the working tree — so a `monorepo` canary pinned the
channels family to its last stable release even when the commit changed both
sides of the contract. Add a prerelease-only `all` selector that bumps and
publishes every scope from one commit under one shared canary id, and warn
loudly when a single-scope canary leaves a cross-scope pin behind.
`all` is a selector, never a scope: stable releases stay single-scope (their
tag, release branch, and npm/Slack links all derive from one scope name), which
publish-release.yml enforces in both jobs and the dropdown guard enforces per
workflow.
The packed Channels umbrella (and the runtime-package verify) install
first-party packages straight from the registry, so a just-published
@copilotkit/* version fails pnpm's 24h minimumReleaseAge check — this is
what reddened `unit (20.x)` on channels PRs. The enumerated exclude lists
drift every time an internal dependency is added (main already had to bolt
on @copilotkit/channels-core, then #6012 added @copilotkit/core + shared).
Wildcard the @copilotkit/* scope (org-owned, same publish pipeline — no
outsider can inject a package, and it stops the drift). Keep @ag-ui
enumerated rather than wildcarded: it's a separate upstream org, so we don't
extend immediate-install trust to its entire scope. Third-party deps stay
fully gated. Applied to both the generated consumer workspace and the
repo-root .npmrc.
Verified: `pnpm run verify:channels-umbrella` installs the packed umbrella
with no ERR_PNPM_NO_MATURE_MATCHING_VERSION; umbrella unit tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Renames the Bots SDK to the Channels SDK. Names only — no behavior change.
- 8 packages @copilotkit/bot* -> @copilotkit/channels* (git mv dirs, names,
workspace: cross-deps). Now includes @copilotkit/bot-intelligence ->
@copilotkit/channels-intelligence (landed on main via #5761; unpublished, so
renamed fresh with the family).
- release.config.json scope keys + versionSource; ReleaseScope union;
canary/stable-release/publish-release scope dropdowns; verify script
- examples/slack (Kite) + examples/teams: deps, jsxImportSource, imports
- showcase/shell-docs: content dirs docs/bots->docs/channels and
reference/bot->reference/channels, nav registry, redirects
createBot and other API names unchanged. Old @copilotkit/bot* to be deprecated
after the new packages publish (bot-intelligence was never published).
Re-derived onto latest main (was conflicting after #5761 landed).
Refs OSS-438
Brings the 499-commit-stale foundations branch up to date with main so #5761
has a clean diff and no stale reverts (e.g. forwardHeaders). Conflicts:
- CopilotThreadsDrawer.tsx: took main's (main renamed CopilotDrawer -> ThreadsDrawer
+ added the collapse feature; the branch's edit was a no-op import-type split).
- pnpm-lock.yaml: regenerated with the pinned pnpm 10.33.4 (adds @copilotkit/bot-intelligence).
Move the Intelligence-delivered managed-bot surface out of @copilotkit/bot into
its own package so the adapter, transports, contracts, and lifecycle ship
independently of bot core.
- New @copilotkit/bot-intelligence: intelligenceAdapter + DeliverySource/EgressSink
(+ in-memory impls) + placeholder contracts + startManagedBots/validation/
activation metadata. Production code imports only types from @copilotkit/bot
and @copilotkit/bot-ui.
- @copilotkit/bot keeps the generic PlatformCodec seam (moved to src/codec.ts) and
all core createBot changes (addAdapter, deferred store, id fields,
__managed/skipIngressDedup, exclusive guard). It now also exports the
FakeAdapter/FakeAgent test utilities for downstream adapter-package tests.
- Registered the new release scope: release.config.json, scripts/release/lib/
config.ts, and the canary/publish/stable release workflows.
Tests preserved: bot 150 + bot-intelligence 19 (= the prior 169); bot-slack 261.
Builds typecheck across bot/bot-intelligence/bot-slack/runtime; publint/attw/
oxlint/oxfmt clean.
The StateStore interface and the in-memory MemoryStore default remain;
durable backends can be reintroduced as a follow-up. Both adapter packages
were merged in #5613 but never published to npm, so removal is a clean
delete with no consumer impact.
- Delete packages/bot-store-redis and packages/bot-store-postgres.
- Revert the bot release scope and drift guard to bot + bot-ui.
- Strip the Redis dep, demo:restart script, restart demo, docker-compose,
and REDIS_URL env from examples/slack.
- Rewrite the bot persistence/transcripts docs around "MemoryStore default
+ implement the StateStore interface yourself for durability".
Adds a durable persistence layer for @copilotkit/bot, replacing the
in-memory-only ActionStore with a pluggable StateStore.
- StateStore interface (kv/list/lock/dedup/queue) with a shared
conformance suite; MemoryStore default plus @copilotkit/bot-store-redis
and @copilotkit/bot-store-postgres backends.
- createBot({ store }): typed per-thread state via Standard Schema,
action snapshots persisted through the store, per-conversation turn
lock (onLockConflict drop|force), and inbound-event dedup keyed on a
stable eventId. ActionStore is kept as a deprecated alias.
- Cross-platform transcripts (bot.transcripts + identity resolver) with
age-bounded retention (prune on append + filter on read), and
runAgent({ transcript: true }) to auto-inject history and capture the
reply.
- createBot({ components }) re-registers components so durable actions
re-fire after a restart; restart-durability demo in examples/slack.
- Dedup is marked seen only after the turn lock is acquired, so a turn
dropped on lock-conflict does not burn its eventId (no lost retries).
- Release lockstep: bot-store-redis/postgres version with bot + bot-ui.