Follow-up to the OSS-473 clean-break rename (#5963). Scrubs the last
internal "bot" vestiges deliberately left out of 473's atomic
telemetry-surface commit. Naming-only, no behavior change.
- `bot` local variable → `channel` in create-channel.ts factory internals
and the ~15 test files that exercise it.
- `BotNode` type → `ChannelNode` in @copilotkit/channels-ui and every
importer (channels, slack/teams/discord/telegram/whatsapp/intelligence
adapters, and the slack/teams examples).
- `botName` adapter-SPI option → `channelName`: renamed on
AdapterStartContext, its create-channel caller, and the one adapter that
reads it (IntelligenceAdapter.start ctx) in the same change so the SPI
cannot drift. The Phoenix wire contract was already `channelName` (473).
- Stale `bot-ui`/`bot-slack` package refs and "bot core"/"the bot" prose in
channels/channels-ui comments → `channels-ui`/`channels-slack`/"channel".
- `Symbol.for("copilotkit.bot-ui.*")` → `"copilotkit.channels-ui.*"`.
Deliberately kept: the platform `isBot?` author flag (an unrelated
"is this message author a bot account" semantic), and example `bot`
instance variables / "demo bot" prose (user-facing, out of this ticket's
internal-symbol scope).
Validation: DoD grep returns zero internal bot symbols in
packages/channels + packages/channels-ui; check-types + test green across
all 8 channels packages (1093 tests) and both examples.
Managed getHistory (app-api /api/bots/history) doesn't include the in-flight
turn — unlike native adapters whose getHistory rebuilds the live thread — so
runAgent({context}) alone runs the agent with zero messages (→ provider 400).
Pass the current message (contentParts ?? text) as `prompt`, the sanctioned
mechanism for input not in the adapter's reconstructed history. Verified live:
the managed Slack bot now returns a real answer over the Phoenix loop.
The realtime primitives (startManagedBots, connectPhoenixHostedBotChannel,
PhoenixRealtimeTransport) existed but nothing composed them into a launcher, so
the managed path defaulted to HTTP and Phoenix was never actually used.
- startManagedBotsOnChannel(bots, { channel, scope, runtimeInstanceId }) — wraps
an already-connected channel in a PhoenixRealtimeTransport (delivery source +
render sink) and starts the bots via startManagedBots. Split out so the
behavior is unit-testable against a fake channel.
- startManagedBotsOverPhoenix(bots, config) — thin glue: connect the gateway
bot-IO channel, delegate, disconnect on stop().
- phoenixEgress: fail-loud EgressSink (Phoenix routes all egress through the
render sink).
- examples/slack/app/managed.ts — a REAL consumer of the launcher: the same
Slack bot as index.ts (agent/tools/context/commands/handlers identical) run in
managed mode over Phoenix instead of the native slack() adapter. No native
index.ts changes.
Tests drive a real createBot through the full managed path over a fake channel:
delivered turn → render frame → completion INTENT (never self-ack); throwing
handler → fail intent. Live-stack E2E + manual validation are the OSS-406 proof;
scale-out (Teams, etc.) is OSS-459.
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
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".
Add per-feature demos to examples/slack that narrate per-platform degradation
explicitly rather than failing silently:
- emoji triage — 🐛/🔥/✅ reactions file/escalate/ack via the agent
- /preview — ephemeral draft issue (native only-you on Slack, DM fallback on
Discord/Telegram)
- /file-issue — modal form (Slack rich, Discord text-only, Telegram
conversational fallback)
Also updates the Slack frontend guide (slack.mdx) with the capability matrix.
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.
Resolve event-renderer.ts onRunFinishedEvent: keep the native turn stream open
(finalized in finish()) AND retain the legacy per-message stream drain from main
(#5573) as a no-op-in-native safety net. app/index.ts (telegram adapter from
#5520 + showToolStatus:false) and create-bot.test.ts auto-merged.
- runtime.ts: pass the bridge's forwarded client tools (convertInputToTanStackAI's
tools) into chat() alongside web_search + MCP, so generative-UI cards and the
confirm_write HITL gate work; drop the prompt line that made the model narrate
charts with a trailing "Charting …" sentence (it landed after the image).
- render-chart / render-diagram: post the caption as a header BEFORE the image
(a file upload's message lands a beat after postFile resolves, so caption-first
keeps a stable caption → image order) and drop the false "rendered above" wording.
Depends on the @copilotkit/runtime factory tool-lifecycle fix (#5572) and the
bot-slack HITL/render-order fix (#5573).
`showToolStatus` only gated the legacy `🔧` rows — the native
`task_update` chunks and the pane "is using `tool`…" composer status
ignored it, so there was no single switch to hide tool-call progress.
Promote `showToolStatus` to the master toggle: when `false`, tool progress
is suppressed on ALL surfaces (native chunks, legacy rows, pane status);
tools still run, only the display is hidden. When `true`, the surface is
still chosen by target (native chunks / legacy rows / pane status, the
latter further gated by the pane's own `toolStatus`).
Flip it off in the slack example (`showToolStatus: false`).
Point all @copilotkit/* deps at workspace:* so the example uses local source (the Telegram work is unpublished and depends on the core HITL fix). Add global unhandledRejection/uncaughtException handlers and guard the onMention/onThreadStarted handlers so a failed turn cannot crash the bot. Update deploy docs.
Unify WhatsApp with main's Slack+Discord multi-adapter demo: WhatsApp becomes a
third env-gated platform block in examples/slack/app/index.ts (listening on
Railway $PORT, with a malformed-PORT guard). Keep the platform-aware
senderContext (also fixes the Discord 'Slack user' label); drop the superseded
buildAdapters helper for main's inline per-platform pattern. package.json takes
main's ~0.0.2 bumps + bot-discord and adds bot-whatsapp (workspace:~); README
intro + deploy section cover all three surfaces.
examples/slack now starts a Slack bot and/or a Telegram bot from one platform-neutral app layer, env-conditional on which credentials are set. Neutralized Slack-specific rendering so the shared components work on both platforms: unicode glyphs instead of mrkdwn shortcodes, no Block Kit raw fallbacks, neutral context/tool wording. Migrated the Telegram e2e smoke harness and BotFather setup docs; removed the separate examples/telegram app.
- webhook: don't let GET / health shadow the verify handshake when WHATSAPP_PATH=/
- adapters: fail loud on a malformed PORT instead of binding NaN
- tests: cover the id-only senderContext branch, the 404-regression for the
health route, and the PORT guard
- docs: update README senderContext snippets to the 2-arg signature
Update package READMEs + ARCHITECTURE for the assistant pane, native streaming,
and the new onThreadStarted / setSuggestedPrompts / setTitle surface. Reverse
the slack.mdx callout that told users to delete the assistant scopes (now
required), and enable the pane in the examples/slack manifest (assistant_view +
assistant:write + assistant_thread_* events) with a dev-ex onThreadStarted
greeting and the assistant config.
100% JSX bot at feature parity with the PoC example: issue/page cards,
tables, Chart.js charts, Mermaid diagrams, incident/status/links cards,
a confirm_write HITL gate, and /agent + /triage slash commands.
Registers examples/slack in the pnpm workspace.