Commit Graph

41 Commits

Author SHA1 Message Date
Alem Tuzlak cd11583884 fix(examples): keep slack agent running when an MCP server is unreachable
The triage runtime connected its MCP clients with Promise.all, so a single
unreachable/misconfigured server (bad key, sidecar down, hang) rejected the
whole run and surfaced as a fatal "⚠️ Agent error: Failed to connect to
MCP server" — the bot was dead for every request, even ones needing no MCP.

Connect each server independently (Promise.allSettled) with an 8s timeout,
drop the ones that fail, and let the agent run with whatever's left (web search,
rendering, thread reading, and any MCP that did connect). A per-turn system note
lists any down sources so the model only tells the user a source is unreachable
if they actually ask for it, and never invents data. Connections are retried
each turn, so a transient outage self-heals.
2026-06-25 16:11:44 +02:00
Tyler Slaton edc8a55b9e fix(slack-example): stop reactions from triggering agent 2026-06-24 13:09:53 -07:00
Tyler Slaton 3afb050ebe feat(bot-slack): configure response routing 2026-06-24 11:53:55 -07:00
Alem Tuzlak 107cdad5af feat(slack-example): reaction/ephemeral/modal feature demos
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.
2026-06-23 20:49:38 +02:00
Alem Tuzlak 5ecdee36b8 feat(bot): pluggable StateStore persistence + cross-platform transcripts
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.
2026-06-23 18:33:38 +02:00
Alem Tuzlak f91f5d6968 Merge remote-tracking branch 'origin/main' into feat/bot-whatsapp
# Conflicts:
#	docs/model-allowlist.json
#	docs~origin_main
#	examples/slack/package.json
2026-06-19 17:26:54 +02:00
Alem Tuzlak a4c57b9911 fix(examples/slack): build all bot adapters via glob, not a hardcoded list
The build script enumerated bot-slack/bot-discord/runtime, so it silently
omitted bot-telegram and bot-whatsapp — deploying with TELEGRAM_*/WHATSAPP_*
secrets would fail at runtime because those adapters' dist/ was never built
(start runs via tsx against the workspace packages' compiled output).

Use the nx project glob '@copilotkit/bot*' (+ runtime) so every bot adapter,
including any added later, is built without editing this script.
2026-06-19 17:19:24 +02:00
Alem Tuzlak d92959e68d Merge remote-tracking branch 'origin/main' into feat/bot-whatsapp
# Conflicts:
#	.github/workflows/canary.yml
#	.github/workflows/publish-release.yml
#	.github/workflows/stable-release.yml
#	examples/slack/README.md
#	examples/slack/app/index.ts
#	examples/slack/app/sender-context.ts
#	release.config.json
2026-06-19 16:17:16 +02:00
Alem Tuzlak 699bc9a5c0 fix(examples/slack): build all imported bot packages for deploy
The build script only built bot-slack, bot-discord, and runtime, so
@copilotkit/bot-telegram (plus bot and bot-ui) were never compiled — the
Railway deploy then crashed on `import { telegram } from @copilotkit/bot-telegram`.
Build every workspace package the app imports.
2026-06-19 16:15:25 +02:00
Alem Tuzlak c55dad5cc5 Merge branch 'main' into feat/bot-slack-native-streaming
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.
2026-06-19 15:57:20 +02:00
Alem Tuzlak ed95058e92 chore(examples/slack): adopt released TanStack openai-base strict-schema fix
Bump @tanstack/ai-openai 0.14.4 → 0.15.2 (pins @tanstack/openai-base 0.8.7,
TanStack/ai#790) and @tanstack/ai → 0.32.0. 0.8.7 emits strict:false for tool
schemas outside OpenAI's strict subset in the provider-path function-tool
converter, so MCP tools (e.g. Notion's API-post-search) no longer 400 — no
local patch needed. Verified end-to-end against the live Slack bot.
2026-06-19 15:01:17 +02:00
Alem Tuzlak 319d0ec78a feat(examples/slack): wire frontend tools into the TanStack agent + tidy render output
- 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).
2026-06-19 14:05:01 +02:00
Alem Tuzlak d4d6e204f1 feat(examples/slack): add web search via a TanStack AI factory agent
The example's runtime agent needed OpenAI's hosted `web_search` tool, but
BuiltInAgent's classic `tools` only accepts handler-based `ToolDefinition[]`
(needs `execute`) — it can't carry a provider/hosted tool. So switch the
agent to BuiltInAgent **factory mode** (`type: "tanstack"`) and drive it with
TanStack AI's `chat()`:

- `openaiText(model)` adapter (OpenAI Responses API; gpt-5.5 default)
- `webSearchTool({ type: "web_search" })` provider tool (`@tanstack/ai-openai/tools`)
- Linear/Notion MCP via `@tanstack/ai-mcp` `createMCPClient` (HTTP + bearer),
  created per-run; `chat()` discovers their tools and closes the connections
- `convertInputToTanStackAI(ctx.input)` bridges AG-UI input → `chat()`;
  BuiltInAgent converts `chat()`'s stream back to AG-UI events

OpenAI-only now (web search is OpenAI-specific); AGENT_MODEL accepts a bare
OpenAI id or an "openai/<id>" form. Adds @tanstack/ai, @tanstack/ai-openai,
@tanstack/ai-mcp to the example.
2026-06-19 14:02:43 +02:00
Alem Tuzlak 340722f597 Merge remote-tracking branch 'origin/main' into feat/bot-whatsapp
# Conflicts:
#	examples/slack/package.json
#	pnpm-lock.yaml
#	showcase/shell-docs/src/content/docs/meta.json
2026-06-19 11:22:56 +02:00
Alem Tuzlak 7fe12d6d3c Merge remote-tracking branch 'origin/main' into feat/bot-telegram-adapter
# Conflicts:
#	examples/slack/README.md
#	examples/slack/package.json
#	pnpm-lock.yaml
2026-06-19 11:04:18 +02:00
Alem Tuzlak 7eb6826466 feat(bot-slack): make showToolStatus the master toggle for tool-call display
`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`).
2026-06-18 19:03:07 +02:00
Alem Tuzlak 6b12589dbd fix(examples/slack): move @ai-sdk/mcp pin to root overrides so it actually applies
The example pinned @ai-sdk/mcp to 1.0.21 (protocolVersion incompat, see
88a2d82) via its own pnpm.overrides. That only took effect when the example
was installed in isolation; as a workspace member pnpm ignores package-level
overrides, so the pin was silently dropped — packages/runtime's `^1.0.21`
could drift to a newer, incompatible 1.x on the next lockfile regen.

Move the override to the root package.json's pnpm.overrides (runtime is the
only consumer, so this enforces exactly 1.0.21 with no wider impact) and
remove the now-dead override from the example (also silences the pnpm warning
that surfaced once the example became a workspace member).
2026-06-18 17:00:04 +02:00
Alem Tuzlak 93074e1c6e ci(examples/slack): drop the standalone lockfile (root workspace lock is authoritative)
`examples/slack/pnpm-lock.yaml` only existed for the old isolated deploy
(root dir `/examples/slack`, `pnpm install --ignore-workspace
--frozen-lockfile` resolving the @copilotkit/* deps from npm). Now that the
example is a workspace member built from source (`workspace:*`, root-dir
`/`), pnpm uses the single root `pnpm-lock.yaml`; the per-example lock is
never consulted and was left stale — it still pins the published `~0.0.2`
versions, which contradicts the `workspace:*` package.json and would break
any `--frozen-lockfile` install.
2026-06-18 16:16:08 +02:00
Alem Tuzlak 2434e36453 ci(examples/slack): build from workspace source to decouple Railway deploy from npm publish
The example declared its sibling @copilotkit/* packages as npm version
ranges, so the Railway service (which builds examples/slack in isolation)
resolved them from the registry — forcing a "publish first, then bump the
example" dance on every PR, with a broken deploy window in between.

Switch those deps to the workspace:* protocol (the example is private, so
it never affects publishing) so the example always builds from in-repo
source, and add a graph-aware `build` script that compiles the workspace
libs it imports (and their deps) via Nx. README documents the Railway
settings (root dir / build / start / watch paths) and the copy-out caveat.

Result: a packages/** change redeploys the example with the new code
immediately, and npm publishing becomes an independent manual step.
2026-06-18 15:39:04 +02:00
Alem Tuzlak 4c31d5a302 chore(examples): drop the standalone pnpm-lock (example is monorepo-only via workspace:* deps; root lockfile governs) 2026-06-18 14:12:27 +02:00
Alem Tuzlak 2930016f93 Merge remote-tracking branch 'origin/main' into feat/bot-telegram-adapter
# Conflicts:
#	examples/slack/.env.example
#	examples/slack/README.md
#	examples/slack/app/index.ts
#	examples/slack/package.json
#	pnpm-lock.yaml
2026-06-18 14:04:42 +02:00
Alem Tuzlak dff780dd84 chore(examples): run on local workspace source plus fail-loud handlers
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.
2026-06-18 13:47:36 +02:00
Alem Tuzlak 2698c7efa2 Merge origin/main into feat/bot-whatsapp
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.
2026-06-18 12:24:22 +02:00
Alem Tuzlak b703809a1a fix(examples): regenerate slack lockfile for @copilotkit/bot-discord 2026-06-18 11:04:28 +02:00
Alem Tuzlak 29d5a9d61d chore(discord): remove unrelated PR changes 2026-06-17 18:32:26 -07:00
Alem Tuzlak 6cec41bf64 feat(examples): run Slack and Discord from one bot app 2026-06-17 11:37:38 -07:00
Alem Tuzlak fc3cc1b395 feat(examples): drive Slack and Telegram from one app
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.
2026-06-17 19:20:00 +02:00
Alem Tuzlak 9d0313761f style: oxfmt whatsapp/slack fold 2026-06-17 15:16:45 +02:00
Alem Tuzlak 03fca76c2c fix(whatsapp-fold): address code review
- 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
2026-06-17 15:14:35 +02:00
Alem Tuzlak bca93eaa04 chore: fold whatsapp demo into examples/slack; delete examples/whatsapp 2026-06-17 14:58:07 +02:00
Alem Tuzlak 079112dee3 feat(slack-example): run WhatsApp as a second adapter with per-turn platform context 2026-06-17 14:50:22 +02:00
Alem Tuzlak e70fc800bc feat(slack-example): env-gated buildAdapters (slack + optional whatsapp) 2026-06-17 14:45:58 +02:00
Alem Tuzlak 21225d8123 feat(slack-example): make senderContext platform-aware 2026-06-17 14:41:51 +02:00
Alem Tuzlak 7c884b931b fix(examples): regenerate standalone slack lockfile for @copilotkit/bot* 0.0.2
examples/slack ships a standalone pnpm-lock.yaml (used by Railway when building
with rootDirectory=/examples/slack). PR #5478 fixed the root workspace lockfile
but not this one, so it still pinned @copilotkit/bot* at ~0.0.1 while
package.json now requires ~0.0.2 — pnpm install --frozen-lockfile failed with
ERR_PNPM_OUTDATED_LOCKFILE on deploy.

Regenerate it with the repo's pinned pnpm (10.33.4) via
pnpm -C examples/slack install --ignore-workspace --lockfile-only: importer
specifiers are now ~0.0.2 resolving to the published 0.0.2, the @ai-sdk/mcp
override is preserved. Verified: CI=true frozen install reports "Lockfile is
up to date" (exit 0).
2026-06-16 17:01:26 +02:00
Alem Tuzlak d6d487ba47 docs(examples): note monorepo deploy watch-paths for slack example
Document that the slack example consumes the published @copilotkit/bot*
packages and that deploys (e.g. Railway) must include the repo-root
pnpm-lock.yaml / package.json in their watch paths, so a dependency bump
triggers a rebuild and a frozen install doesn't fail on an out-of-date
lockfile. Touches examples/slack/** to trigger the Railway redeploy of the
current main (which now carries the deployable-lockfile fix).
2026-06-16 16:01:18 +02:00
Alem Tuzlak ba159ce8e1 chore(examples): bump slack example to @copilotkit/bot* 0.0.2
@copilotkit/bot, @copilotkit/bot-slack, and @copilotkit/bot-ui are published at
0.0.2 (agent-native assistant pane + native streaming). Point the slack
example's dependency ranges at ~0.0.2 so a deployed/standalone install pulls
the new packages. Local monorepo installs already use the workspace copies via
root pnpm.overrides, so the lockfile is unchanged.
2026-06-16 14:22:50 +02:00
Alem Tuzlak be26c104f8 fix(examples): enable Messages tab in slack app manifest (YAML)
The YAML manifest was missing the app_home block the JSON variant has, so
apps created from it showed "Sending messages to this app has been turned
off". Add app_home with the Messages tab enabled (not read-only), matching
slack-app-manifest.json.
2026-06-15 18:34:59 +02:00
Alem Tuzlak a925e33be9 docs(bot-slack): document assistant pane + native streaming; enable in slack example
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.
2026-06-15 15:47:46 +02:00
Tyler Slaton 88a2d82e1a fix(examples/slack): pin @ai-sdk/mcp to 1.0.21 (protocolVersion incompat)
@copilotkit/runtime@1.59.5 declares @ai-sdk/mcp ^1.0.21; fresh installs
resolve 1.0.47, whose MCP client assigns transport.protocolVersion after
the server's initialize response — a getter-only property on
@modelcontextprotocol/sdk@1.29.0's StreamableHTTPClientTransport. Every
MCP-enabled run then fails with:
  TypeError: Cannot set property protocolVersion of
  #<StreamableHTTPClientTransport> which has only a getter

The workspace-tested resolution was 1.0.21 (no such assignment — verified
by source diff of the published tarballs). Pin it via pnpm.overrides until
@copilotkit/runtime supports the newer client line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 15:44:58 -07:00
Tyler Slaton e197b1a46e fix(examples/slack): consume published packages; make the example standalone-deployable
- dependencies: workspace:* -> published ranges (@copilotkit/bot* ~0.0.1,
  @copilotkit/runtime ^1.59.5) — the example is a consumer of the released
  packages, installable and deployable with zero monorepo context
- drop the private @copilotkit/typescript-config devDep; inline the base
  compiler options into tsconfig.json (verified identical tsc result)
- commit a standalone examples/slack/pnpm-lock.yaml for isolated installs
  (root workspace installs ignore it)
- slack-app-manifest.{yaml,json}: remove assistant:write scope +
  assistant_thread_started event (Slack rejects them without an
  assistant_view feature block; the bot doesn't implement that surface),
  add the /triage slash command the bot registers

Verified: slack-example tests 38/38 against the published packages; direct
tsc --noEmit clean; standalone install + runtime/bot boot exercised in a
gitless clean-room snapshot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 14:54:46 -07:00
Alem Tuzlak acf17d6170 feat(examples): Slack on-call triage bot over Linear + Notion MCP
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.
2026-06-10 10:46:08 -07:00