Commit Graph

12110 Commits

Author SHA1 Message Date
Atai Barkai 0a8a4e97ea chore(shell-docs): update MDX remote dependency 2026-06-18 12:15:01 -07:00
Atai Barkai 6598481d8b docs(shell-docs): configure shell docs preview 2026-06-18 12:15:01 -07:00
Atai Barkai 8beaab7b0d docs(shell-docs): refine backend picker ordering 2026-06-18 12:15:01 -07:00
Atai Barkai 3fa0f0dff9 docs(shell-docs): update frontend reference links 2026-06-18 12:15:01 -07:00
Atai Barkai 469afd8f28 docs(shell-docs): add React docs guidance dialog 2026-06-18 12:15:01 -07:00
Atai Barkai c0b1e0a076 docs(shell-docs): split frontend and backend picker 2026-06-18 12:15:01 -07:00
Atai Barkai a49fc266b9 docs(shell-docs): add frontend docs routing 2026-06-18 12:15:01 -07:00
Maxim 9907519989 fix(react-core): honor selfManagedAgents in CopilotKit wrapper validation
The v1 <CopilotKit> wrapper's validateProps threw ConfigurationError
whenever neither runtimeUrl nor a public key was supplied, ignoring
self-managed agents. This rejected the documented self-managed-agent
setup even though the underlying v2 CopilotKitProvider accepts it.
Mirror the provider's hasLocalAgents gate so selfManagedAgents and
agents__unsafe_dev_only satisfy the check.

Closes #5417
2026-06-18 21:11:04 +02:00
Jordan Ritter e31abd1acd feat(showcase): support --isolate=<N> CLI form as sugar over SHOWCASE_ISO_SLOT (#5547)
## Summary

Follow-up to #5543. Adds `--isolate=<N>` CLI form so users don't need to
set `SHOWCASE_ISO_SLOT=<N>` as an env var prefix.

## Before

```
SHOWCASE_ISO_SLOT=9 bin/showcase test agno --d5 --isolate
```

## After (both forms work)

```
bin/showcase test agno --d5 --isolate=9
# OR
SHOWCASE_ISO_SLOT=9 bin/showcase test agno --d5 --isolate
```

## Implementation

~10 lines in `showcase/scripts/cli/cmd-test.sh` arg parser: a new
`--isolate=*` case sets `use_isolate=true` and exports
`SHOWCASE_ISO_SLOT=<N>`. The existing picker (`_claim_isolate_slot` in
`_common.sh`) handles all validation, slot-0 rejection, port-probe,
liveness, etc. — no logic duplication.

Help text in `cmd-test.sh` and the existing `SHOWCASE_ISO_SLOT`
references in `showcase/TESTING.md` now show both forms as equivalent.

## Tests

Four new bats tests in `showcase/scripts/__tests__/isolate.bats`:

- `--isolate=<N> arg form exports SHOWCASE_ISO_SLOT and pins the slot
through the picker` — replays the parser branch, verifies env export +
picker pinning.
- `--isolate=0 arg form drives the picker's reserved-slot rejection` —
proves `--isolate=0` flows through the same `slot 0 is reserved` die as
the env-var form.
- `--isolate=99 arg form drives the picker's out-of-range rejection` —
proves `--isolate=99` flows through the same `exceeds
ISOLATE_MAX_SLOT=45` die as the env-var form.
- `cmd-test.sh --isolate=<N> actually wires the arg through to
SHOWCASE_ISO_SLOT` — drift guard that sources the REAL `cmd-test.sh`,
stubs `apply_isolation`, and snapshots `SHOWCASE_ISO_SLOT` to catch any
future regression of the parser branch.

All 58 bats tests in `isolate.bats` pass locally (54 pre-existing + 4
new).

## Docs

`showcase/TESTING.md` items 8 and 9 updated to show both forms.
Repo-wide grep confirmed TESTING.md is the only doc that references
`SHOWCASE_ISO_SLOT`.

## Test plan

- [x] `bats showcase/scripts/__tests__/isolate.bats` → 58/58 green
- [x] `--isolate=9` → `SHOWCASE_ISO_SLOT` exported, slot 9 claimed
- [x] `--isolate=0` → picker dies "slot 0 is reserved"
- [x] `--isolate=99` → picker dies "exceeds ISOLATE_MAX_SLOT=45"
- [x] `shellcheck showcase/scripts/cli/cmd-test.sh` → no new warnings
(only the pre-existing SC2034 on `CMD_TEST_DESC`, consumed by dispatcher
parallel arrays)
- [x] `oxfmt --check showcase/` → clean
2026-06-18 11:42:03 -07:00
Sam Julien d7dd0e6154 docs(shell-docs): normalize quickstart CTAs (#5544)
## Summary
- remove duplicated OpsPlatformCTA blocks from A2A, CrewAI Flows, and
LangGraph prebuilt components docs
- add missing production CTA cards to integration quickstarts that only
had the inline signup step
- audit shell-docs CTA usage so each integration quickstart has exactly
one OpsPlatformCTA and no duplicate CTA blocks remain

## Verification
- npm run test (showcase/shell-docs)
- npm run typecheck (showcase/shell-docs)
- npm run lint (showcase/shell-docs; existing warnings only)
- npm run build (showcase/shell-docs; existing Next/Turbopack warning
only)
- duplicate CTA scanner: no duplicate CTA blocks found
- quickstart CTA scanner: every integration quickstart has exactly one
OpsPlatformCTA
2026-06-18 11:16:15 -07:00
Sam Julien 33a79485b6 chore(docs): remove retired docs app 2026-06-18 10:54:16 -07:00
Jordan Ritter 0e7e311692 docs(showcase): document --isolate=<N> CLI form in TESTING.md
Items 8 and 9 now show both the SHOWCASE_ISO_SLOT=<N> env-var form and
the --isolate=<N> CLI sugar as equivalent ways to pin the isolation
slot. The env-var form remains valid — the CLI form is a convenience,
not a replacement.

A repo-wide grep confirmed showcase/TESTING.md is the only doc that
references SHOWCASE_ISO_SLOT, so no other docs need updating.
2026-06-18 10:39:08 -07:00
Jordan Ritter ce2d2bcd91 feat(showcase): support --isolate=<N> CLI form as sugar over SHOWCASE_ISO_SLOT
Adds a sugar form of the --isolate flag that pins the isolation slot
directly from the command line:

    bin/showcase test agno --d5 --isolate=9
    # equivalent to:
    SHOWCASE_ISO_SLOT=9 bin/showcase test agno --d5 --isolate

The arg parser splits --isolate=<N> into setting use_isolate=true plus
exporting SHOWCASE_ISO_SLOT=<N>; the existing picker
(_claim_isolate_slot in _common.sh) handles all validation — positive
integer, slot 0 reserved, 1<=N<=ISOLATE_MAX_SLOT, port probe, liveness.
No validation logic is duplicated.

Tests:
- replays the parser branch and verifies SHOWCASE_ISO_SLOT export +
  picker pinning
- drives the picker's reserved-slot (N=0) and out-of-range (N=99)
  rejections through the arg form to pin the parser->env->picker wiring
- drift guard: sources the REAL cmd-test.sh, stubs apply_isolation, and
  snapshots SHOWCASE_ISO_SLOT to catch any future regression of the
  parser branch

Help text and TESTING.md updated in a follow-up commit.
2026-06-18 10:38:55 -07:00
Sam Julien 356b3320c3 docs: add Codex docs editing guidance (#5546)
## Summary
- add Codex-facing guidance for where CopilotKit docs are authored
- call out shell-docs, framework docs modes, reference nav, snippets,
AG-UI upstream docs, and retired top-level docs
- clarify shell-docs local work should use the shell-docs npm commands

## Verification
- lefthook pre-commit hooks passed during commit
- commit-msg hook passed
2026-06-18 10:36:30 -07:00
Sam Julien b7092c49fb docs: fix CrewAI Flows quickstart init command (#5545)
## Summary
- Update the CrewAI Flows quickstart init command to use the
CLI-supported framework flag.

## Verification
- Ran shell-docs predev generation as part of local dev server startup.
- Opened http://localhost:3004/crewai-crews/quickstart and verified the
rendered page snapshot contains: `npx copilotkit@latest init --framework
flows`.
- Commit hook passed: check-binaries, test-and-check-packages,
commitlint.
2026-06-18 10:35:00 -07:00
Sam Julien baf5db256f docs(agents): add docs editing guidance for codex 2026-06-18 10:30:47 -07:00
Alem Tuzlak 02be193fcc ci(release): make @copilotkit/bot-discord a releasable scope 2026-06-18 19:28:25 +02:00
Sam Julien fcc43cf344 docs: fix CrewAI Flows quickstart init command 2026-06-18 10:27:44 -07:00
Jordan Ritter baf355ee21 feat(showcase): fix --isolate slot picker (pinning, port probe, slot 0 reservation, bin/showcase slots) (#5543)
## Summary

Fixes the `--isolate` slot picker in `showcase/scripts/cli/_common.sh`
and adds a new `bin/showcase slots` inspector subcommand. Resolves five
compounding bugs that made multi-agent local testing unreliable.

## Bugs fixed

1. **`SHOWCASE_ISO_SLOT=<N>` env var was ignored.** The picker walked
0→N regardless. Now: validates input (positive integer, `1 ≤ N ≤ 45`,
slot 0 rejected as base stack), tries exactly that slot, fails loudly on
conflict.
2. **No port-probe before commit.** Picker `mkdir`'d a slot dir without
checking whether the slot's host ports were free. A slot whose dir was
absent but whose ports were taken (foreign Docker project, host service
like macOS AirPlay on 5000) was picked then failed at `docker compose
up`. Now: `lsof`-probe every candidate port before committing the claim;
rmdir + try next on conflict.
3. **Slot 8 / port 5000 collision on macOS.** Base dashboard port `3200`
+ slot 8 offset `+1800` = `5000`, permanently bound by macOS Control
Center's AirPlay Receiver. Shifted dashboard base port `3200 → 3210`
across `docker-compose.local.yml` and `showcase/harness/src/cli/*.ts` so
slot 8 → port `5010` (free).
4. **Slot ownership desync across 3+ independent owners.** Picker
checked only the dir; sweeper checked dir+pid+containers; neither
checked foreign ports. New unified `_slot_state` returns all 4 axes
(dir/pid/liveness/ports/offset/project); new `bin/showcase slots`
exposes the state via table / `--json` / `--free --brief` filters.
5. **Parallel pre-claim deadlock dissolved** by bugs 1+2+4 — per-session
pinning via env var + accurate port-probe + atomic `mkdir` lock
self-resolves contention.

## Implementation

- New helpers in `_common.sh`: `_slot_offset_ports`, `_slot_liveness`
(extracted from sweeper), `_slot_ports_free` (with own-project
docker-listener filter), `_slot_state` (composite axis report).
- Rewritten `_claim_isolate_slot`: pinned-path (validate / try / die
loudly) and auto-pick-path (1..MAX_SLOT, rmdir + skip on port-held).
Slot 0 reserved with explicit die message.
- `ISOLATE_MAX_SLOT=45` centralized as a constant.
- Dashboard host port shift `3200 → 3210` across 6 files (compose + 4
harness TS + comment updates).
- New `cmd-slots.sh` plugin (auto-discovered by `bin/showcase`): default
table, `--json` (JSONL), `--free` (filter to claimable slots), `--brief`
(numeric IDs only).

## Tests

**Bats — 54/54 GREEN** in `showcase/scripts/__tests__/isolate.bats`:

- 12 pre-existing tests updated for slot-0-reservation contract
(reap-evidence assertions preserved; only slot-number / port-offset
expectations updated).
- 11 new tests added:
  - lsof stub + foundation smoke (test #0)
- Pinning behavior tests #1-3 (success, live-die, validation incl.
0/foo/99)
- Port-probe tests #4-7 (stale-reap, `_slot_offset_ports 8 → 5010 ≠
5000`, foreign-process skip, own-project no-skip)
- Composite tests #8-10 (`_slot_state` 5 axes, `bin/showcase slots`
output, concurrent claim distinct slots)
- lsof-graceful test (#54): `_slot_state emits ports=? when lsof is
unavailable`

**Vitest — 17/17 GREEN** in
`showcase/harness/src/cli/control-plane-run.test.ts` (port-shift stub
consistency).

**Value-test (live local, plan §6 scenarios) — all 3 PASS:**

- **Scenario A:** On the test host Docker was holding slot 9's ports, so
the picker correctly REFUSED `SHOWCASE_ISO_SLOT=9` with per-port
diagnostics (proving the fail-loud half of the contract). Re-ran with
`SHOWCASE_ISO_SLOT=15` (first free slot) and the pin was honored
cleanly: `ISOLATE_SLOT=15`, `OFFSET=3200`. Both halves of the pin
contract verified.
- **Scenario B:** Slots 1-7 pre-occupied with live pids + Python
listener on `127.0.0.1:5010` (slot 8's dashboard port) → picker logged
"Slot N ports held" + "trying next" for each conflict, walked past 9..13
(Docker-held), and landed on slot 14 with `OFFSET=3000`. No silent
collision.
- **Scenario C:** `bin/showcase slots` matches reality: slot 0 →
`OFFSET=+0 PROJECT=showcase (base)`; pre-claimed slot 5 → `DIR=present
PID=<pid> LIVE=live PORTS=held OFFSET=+1200 PROJECT=showcase-iso5-test`.
`--free --brief` outputs only fully-claimable slot IDs (44 in this run,
slot 5 excluded).

## Code review

Full 7-agent cr-loop with `pr-review-toolkit` reviewers (Round 1 +
confirmation round). 4 subject-scope load-bearing findings fixed:
- `_reap_isolate_slot` arg shape in pinned-path retry
- `_slot_state` base-stack offset (slot 0 → `+0`, not `+200`)
- TESTING.md item 8/9 column-name accuracy (matches actual `SLOT DIR PID
LIVE PORTS OFFSET PROJECT` header)
- `bin/showcase slots` lsof-graceful degradation (inspector reports
`PORTS=?` instead of dying when `lsof` is missing)

Plus 1 trivial comment-phrasing fix (race-comment wording). ~50
pre-existing harness/compose findings partitioned out-of-subject and
deferred to follow-up PRs (see below). Procedure 3 bucket-(c) promotion
audit returned zero PROMOTE_TO_A items — full convergence.

## Follow-up PRs (out-of-subject, separate subjects)

These coherent subjects surfaced during CR but belong to distinct PRs
(the diff merely brushed against them for the `3200→3210` shift):

- **d1** — Harness `up()` / `doctor` should health-check
`harness-control-plane` (port 8081). `_slot_offset_ports` includes 8081;
`INFRA_PORTS` in `doctor.ts` / `lifecycle.ts` does not.
- **d2** — `doctor.ts` port + image diagnostic loud-failure pass
(`checkStaleImages`, `checkPorts`, `isPortListening`,
`checkDepotInterception` swallow errors).
- **d3** — `lifecycle.ts` error-surfacing pass (broad catches in
`loadPortsFile`, `isRunning`, `compose`, `healthCheck`, `diffLogs`,
etc.).
- **d4** — `docker-compose.local.yml` healthcheck error visibility
(`.catch(() => process.exit(1))` swallows; dashboard `/` returns 307).
- **d5** — `apply_isolation` Python rewriter fail-loud pass (no
`re.subn` count checks, hand-rolled YAML demos parser).
- **d6** — Centralize infra port literals (currently duplicated in 4
places).
- **d7** — `lifecycle.ts:11-13` stale `ops/` path comment (file lives at
`harness/`).
- **d8** — `cmd_slots --json` `pid` field typing (string vs number) —
settle when first JSON consumer appears.

## Test plan

- [x] `bats showcase/scripts/__tests__/isolate.bats` → 54/0
- [x] `pnpm vitest run src/cli/control-plane-run.test.ts` (in
`showcase/harness/`) → 17/0
- [x] `pnpm exec tsc --noEmit` (in `showcase/harness/`) → clean
- [x] `oxfmt --check showcase/` → clean
- [x] `docker compose -f showcase/docker-compose.local.yml config` →
valid YAML
- [x] Local value-test scenarios A/B/C from plan §6 → PASS
2026-06-18 10:25:34 -07:00
Sam Julien ddeeb9c586 docs(shell-docs): add missing quickstart CTAs 2026-06-18 10:16:07 -07:00
Sam Julien 6e301f0247 docs(shell-docs): remove duplicated CTA blocks 2026-06-18 10:12:42 -07: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
Austin Merrick a4c5331e6f docs: fix LangGraph documentation links (#5445)
Closes #3190.

## Summary
- update the configurable guide links to the current LangGraph
use-graph-api documentation
- remove an encoded `%23` fragment from the runtime configuration link
- point the AI travel tutorial Studio setup link directly to the current
LangGraph Studio docs

## Verification
- `npx --yes prettier --check
docs/content/docs/integrations/langgraph/configurable.mdx
docs/content/docs/integrations/langgraph/tutorials/ai-travel-app/step-2-langgraph-agent.mdx`
- `git diff --check`
- checked the updated LangChain/LangGraph URLs with `curl -L -I` and
confirmed HTTP 200

Note: `node scripts/check-broken-links.js` was also attempted from
`docs/`, but this sparse checkout does not include all docs pages and
lacks `fumadocs-mdx`, so it reports pre-existing missing internal pages
unrelated to this docs-only change.
2026-06-18 09:49:05 -07:00
Benjamin Taylor e149fe7dc3 chore(examples): drop dead _intelligence overlay pointers from 8 .env.example
The deleted examples/integrations/_intelligence/ dir was referenced by a
"see .../.env.intelligence for the seed value" comment on the
INTELLIGENCE_API_KEY line in 8 integration .env.example files. Removing the
overlay leaves those pointers dangling, so strip them in the same PR.

Localhost INTELLIGENCE_API_URL/GATEWAY_WS_URL defaults are intentionally left
in place — the hosted-only rewrite of those is a launch-coordinated follow-up
(depends on the managed CLI env contract).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 11:38:18 -05:00
Benjamin Taylor dbb36628f8 chore(examples): remove live-consumed _intelligence overlay (ENT-834)
Removes examples/integrations/_intelligence/ — the docker-compose +
.env.intelligence + README overlay that the currently-shipped CLI clones
at runtime from CopilotKit@main via fetchIntelligenceOverlay.

DRAFT — do NOT merge until the managed-only CLI build has dropped
fetchIntelligenceOverlay (Intelligence-repo removal) AND been released.
Deleting this dir from main before then breaks the shipped CLI's
threads-framework init (overlay fetch 404s). Merge in lockstep with launch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 11:38:18 -05:00
Austin Merrick 4129a0aedf ci(plugin-skills): trigger drift check on runtime package.json changes
The plugin version pins to packages/runtime/package.json, but neither the
lefthook glob nor the plugin-skills-check workflow path filters watched
that file. A routine release bump to the runtime version therefore matched
no trigger and the pin silently rotted between releases (the root cause of
the version drift). Add packages/runtime/package.json to the lefthook glob
and to both the push and pull_request path filters so a version bump
re-runs check:plugin-skills.
2026-06-18 09:23:03 -07:00
Austin Merrick 2829daff03 fix(plugin): sync marketplace metadata.version and re-pin to runtime 1.60.2
The plugin version pins to packages/runtime/package.json, but plugin.json
(1.60.0) and marketplace.json (plugins[0] 1.60.0, metadata 1.57.3) had
rotted behind the runtime package (1.60.2), so check:plugin-skills was
failing on main.

handleVersionSync previously managed only plugin.json.version and
marketplace plugins[0].version, leaving marketplace metadata.version
unmanaged and free to drift independently. Extend it to track
metadata.version against the runtime version too, and re-run the sync to
bring all three fields to 1.60.2.
2026-06-18 09:23:03 -07:00
Mike Ryan b8c2cac17b feat(react-core): expose toolCallId & agentId on HITL render props (#5539)
## Summary

Adds two optional attribution props — `toolCallId` and `agentId` — to
the `useHumanInTheLoop` render callback (`ReactHumanInTheLoop`), so a UI
can tell **which (sub)agent raised an interrupt** and route/resume it
accordingly. This is the front-end piece needed to render and act on
human-in-the-loop stops that originate from a subagent (the
orchestrator/subagent pattern).

Backward compatible and additive — existing HITL render components are
unaffected. No AG-UI protocol change and no runtime change: `toolCallId`
already flowed to the renderer at runtime (this surfaces it in the
type), and `agentId` is sourced from the tool's own registration.

## What changed

- **`types/human-in-the-loop.ts`** — add `toolCallId: string` and
`agentId?: string` to all three render-prop variants, with JSDoc on the
static-vs-runtime distinction.
- **`hooks/use-human-in-the-loop.tsx`** — thread `agentId: tool.agentId`
into the enhanced props; compare `props.status` against the
`ToolCallStatus` enum (was string literals); replace the unreachable `as
any` fallback with a compile-time exhaustiveness check.
- **tests** — assert `toolCallId`/`agentId` reach the render props
through the real `CopilotChat` pipeline (scoped + unscoped), and that
attribution survives the `InProgress → Executing` transition.
- **docs** — document the two new props on the `useHumanInTheLoop`
reference page.

## Decision needed from reviewers — `agentId` semantics

`agentId` is the tool's **static registration scope** (`tool.agentId`),
which is `undefined` for the default unscoped tool — it is **not** the
runtime subagent that raised the interrupt. `toolCallId` is the
load-bearing addition: correlate it with `onToolExecutionStart`'s agent
id for true runtime attribution. The JSDoc states this explicitly.
Options if we want to avoid any ambiguity:
1. **Keep as-is** (documented static scope) — current state.
2. Rename → `registeredAgentId`.
3. Drop `agentId`, ship `toolCallId`-only.

## Follow-ups (separate PR — not in scope here)

These are pre-existing in the HITL `respond`/registration layer
(untouched by this diff) and are the deeper work for full subagent HITL:
- **Route `respond` by `toolCallId`** — a single `resolvePromiseRef`
can't service concurrent interrupts of the *same* tool
(cross-wire/hang). Key resolvers by `toolCallId`.
- **`respond` failure path** — currently a silent no-op when no resolver
is pending, and the handler promise has no rejection on unmount/abort.
- **Re-registration on dynamic `agentId` change** — `useFrontendTool`'s
registration effect deps omit `agentId`/`render`.

## Verification

- `nx run @copilotkit/react-core:test` — 1281 passing (incl. the new
attribution tests).
- `react-core` typecheck clean for the change; `react-core:build` green.
- Reviewed via a 3-round, 7-agent unbiased CR loop; converged with the
bucket-(c) promotion audit clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-06-18 09:19:27 -07:00
GeneralJerel c94184daf9 docs(cookbook): retitle and sync recipe with the current demo
Retitles to 'Build an Agentic Travel App with Oracle Agent Memory, Agent Spec, and CopilotKit' and syncs the recipe with the latest example: adds the memory-ownership diagram + 'what's CopilotKit, what's Oracle' section, documents memory reconciliation/supersession, and updates booking + multi-turn guidance (follow-ups now work via a server-side history-replace). Keeps the CDN media + clone conventions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 09:18:07 -07:00
David McKay cfca586da7 docs(react-core): document toolCallId and agentId on useHumanInTheLoop render props
The render-callback reference omitted the always-present attribution props.
Document toolCallId (the per-interrupt correlation key) and agentId (static
registration scope, undefined for unscoped tools), matching the type's JSDoc.
2026-06-18 11:05:41 -05:00
David McKay 0098840d42 test(react-core): assert HITL attribution survives the status transition
Extend the unscoped-tool attribution test to verify toolCallId persists and
agentId stays undefined after the tool moves InProgress -> Executing, not just
at InProgress.
2026-06-18 10:58:47 -05:00
David McKay ca07dcad63 refactor(react-core): exhaustiveness check for HITL render fallback
Code-review follow-up. Replace the unreachable `as any` fallback branch with
a compile-time exhaustiveness check (const _: never = props): a newly-added
ToolCallStatus now becomes a type error that must get its own branch, rather
than silently rendering with respond=undefined. Also correct the prop-build
comment (name/description are overwritten with the registration values, not
'normalized'). No behavior change for the three live statuses.
2026-06-18 10:58:42 -05:00
David McKay b8f6856b48 fix(react-core): accurate HITL attribution docs + defensive render fallback
Addresses code-review findings on the HITL attribution change:
- Correct the render-prop JSDoc: agentId is the tool's STATIC registration
  scope (undefined for unscoped tools), not the runtime sub-agent; toolCallId
  is the key to correlate with runtime attribution (onToolExecutionStart /
  event stream). Removes the over-claim that agentId resumes 'the correct
  sub-agent'.
- Compare props.status against the ToolCallStatus enum instead of string
  literals (removes silent drift risk).
- Inject name/description/agentId in the otherwise-unreachable fallback branch
  so attribution is never silently dropped if a status is ever added; cast
  the narrowed-never props to a record so the spread typechecks.

Behavior-preserving for the three live statuses; e2e suite green (13/13).
2026-06-18 10:51:52 -05:00
David McKay 93d3d80d80 feat(react-core): expose toolCallId and agentId on human-in-the-loop render props
The HITL render callback received args/status/result but no attribution, so
a UI could not tell which run raised an interrupt — the blocker for rendering
and resuming human-in-the-loop stops that originate from a subagent.

- Add toolCallId (already delivered at runtime via the renderer props spread;
  this only surfaces it in the type) and agentId (sourced from the tool's own
  registration) to all three ReactHumanInTheLoop render-prop variants.
- Thread agentId through useHumanInTheLoop's enhanced props.
- e2e tests assert both reach the render props through the real CopilotChat
  pipeline, and that agentId is undefined for an unscoped tool.

No shared renderer-contract or dispatch changes; no runtime behavior change.
2026-06-18 10:42:30 -05:00
Alem Tuzlak 1ae850ef8c fix(examples/slack): finish the Railway workspace-source deploy (Node 22 pin + @ai-sdk/mcp root override) (#5538)
Two small follow-ups to #5534 (which made `examples/slack` build from
workspace source) needed to make the Railway deploy actually succeed.

## 1. Pin Node 22 (`.nvmrc`) — the deploy blocker

#5534 merged **without** the Node pin, so Railway still builds on **Node
18**. Now that the build compiles the `@copilotkit/*` libs from source
(tsdown/rolldown), it needs **Node ≥20.12** (`node:util`'s `styleText`)
and fails on 18:

```
SyntaxError: The requested module 'node:util' does not provide an export named 'styleText'
Node.js v18.20.8
```

The builder defaults to 18 from root `engines.node: ">=18"`. A root
**`.nvmrc` = 22** pins the build/dev Node (read by the Railway builder
and nvm/fnm). CI is unaffected (no workflow reads `.nvmrc`), and the
published `engines` runtime contract is left as-is — a build-environment
pin, not a runtime change.

> If your builder ignores `.nvmrc`, set `NIXPACKS_NODE_VERSION=22` on
the service as a fallback.

## 2. Move the `@ai-sdk/mcp` pin to root `pnpm.overrides`

The example pinned `@ai-sdk/mcp` to `1.0.21` (protocolVersion incompat —
`88a2d82`) via its **own** `pnpm.overrides`. That only worked installed
in isolation; as a workspace member pnpm ignores package-level
overrides, so the pin was silently dropped (and pnpm warns).
`packages/runtime` allows `^1.0.21`, so a future lockfile regen could
drift to a newer, incompatible 1.x. Moved it to the **root**
`pnpm.overrides` (runtime is the only consumer) and removed the dead one
from the example.

> Pre-commit `test-and-check-packages` bypassed: the lockfile change
makes nx mark everything affected, and the only failure is the
pre-existing, environmental `@copilotkit/sqlite-runner:test` (native
sqlite on Node 24).
2026-06-18 17:12:45 +02:00
Alem Tuzlak d19134cfc0 ci: pin Node 22 via root .nvmrc for the workspace-source build
Re-lands the Node pin that was lost when #5534 merged without it. The
Railway slack-example build now compiles the @copilotkit/* libs from source
(tsdown/rolldown), which needs Node >=20.12 (`node:util`'s `styleText`), but
the builder defaults to Node 18 from the root `engines.node: ">=18"` —
failing with "does not provide an export named 'styleText'". Pin the
build/dev Node to 22 (read by the Railway builder and nvm/fnm). CI is
unaffected (no workflow reads .nvmrc) and the published `engines` runtime
contract is left as-is.
2026-06-18 17:04:57 +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
Nathan 🔶 Tarbert 62acb88f28 revert(react-core): drop useRenderTool schema-free named overload
Per review, keep this PR docs-only. Restores defineToolCallRenderer and
useRenderTool (and its test) to main. The specific-tool opt-out example
now passes a pass-through schema (parameters: z.any()) since the named
overload requires a schema.
2026-06-18 10:36:41 -04:00
Alem Tuzlak bd74f55f36 ci(examples/slack): build from workspace source to decouple Railway deploy from npm publish (#5534)
## Problem

`examples/slack` is deployed on Railway and declared its sibling
packages as **npm version ranges** (`@copilotkit/bot: ~0.0.2`, …).
Because the service resolves those from the registry, every PR that
changes the packages required a brittle dance:

1. Merge → Railway redeploys → installs the **old** published packages →
broken/stale.
2. Manually release the npm packages.
3. Bump the example's versions → that change finally triggers a redeploy
that pulls the new release.

A chicken-and-egg with a broken-deploy window in between.

## Fix

Consume the siblings via the **`workspace:*`** protocol (the example is
`private`, so this 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.

- `examples/slack/package.json`: `@copilotkit/bot`, `-slack`,
`-discord`, `-ui`, `runtime` → `workspace:*`; new `build` script (`nx
run-many -t build -p @copilotkit/bot-slack @copilotkit/bot-discord
@copilotkit/runtime`).
- `pnpm-lock.yaml`: regenerated (drops the registry trees those deps
pulled).
- README: documents the Railway settings and the copy-out caveat.

As a side benefit, this also removes the local "rebuild → re-sync
injected copy" friction — `workspace:*` symlinks the packages, so a
rebuilt `dist` is seen live.

## Required Railway config (apply in the dashboard)

The service must build **as a workspace member from the repo root** —
`packages/**` lives above `examples/slack`, so a service rooted at
`/examples/slack` cannot watch or build it.

| Setting | Value |
|---|---|
| **Root Directory** | `/` (repo root) — **change from
`/examples/slack`** |
| **Build Command** | `pnpm install && pnpm --filter slack-example
build` |
| **Start Command** | `pnpm --filter slack-example start` (bot) / `pnpm
--filter slack-example run runtime` (runtime) |
| **Watch Paths** | `packages/**`, `examples/slack/**`,
`pnpm-lock.yaml`, `package.json` |

## Result

- A `packages/**` change redeploys the example with the new code
**immediately** — no release required.
- `npm publish` becomes an **independent, manual** step. No more
publish-then-bump dance.

## Verification

- `pnpm --filter slack-example build` ✓ (builds 3 libs + 5 deps via Nx)
- `pnpm --filter slack-example check-types` ✓
- `pnpm --filter slack-example test` ✓ (38 tests)

> Pre-commit `test-and-check-packages` was bypassed for the commit: the
lockfile change makes nx mark everything affected, and the only failure
is a pre-existing, environmental `@copilotkit/sqlite-runner:test` break
(native sqlite on Node 24) unrelated to this change.
2026-06-18 16:24:20 +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 80e95f26d4 ci(release): make @copilotkit/bot-telegram a releasable scope 2026-06-18 15:50:23 +02:00
Alem Tuzlak f9b54fea2c chore(release): enroll @copilotkit/bot-whatsapp in the manual release config
Add a bot-whatsapp release scope to release.config.json and the matching
workflow_dispatch scope dropdowns in publish-release / stable-release / canary,
so the package can be released via the manual CI trigger like bot-slack.
2026-06-18 15:50: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 69ad31817c fix(bot-telegram): resilient dispatch, reply context, and text-file decode
Fire agent turns async so a blocking HITL awaitChoice cannot pause grammy sequential polling (which deadlocked the poll loop and drained the process). Add a bot.catch error boundary so update-processing errors are logged and polling continues. Fold a replied-to message (media + quoted text) into the turn. Decode text-like uploads (CSV/JSON/XML/text) to a text part instead of an unsupported binary file part.
2026-06-18 13:47:35 +02:00
Alem Tuzlak 82aea01339 fix(bot): resolve HITL choice value from the rendered element
awaitChoice resolved the waiter with evt.value, which platforms whose callback payload cannot carry it (Telegram, 64-byte callback_data) deliver as undefined. The registry now returns the clicked element value from dispatch, and create-bot falls back to it when the event has none. Slack (value-in-payload) is unchanged.
2026-06-18 13:47:33 +02:00
Alem Tuzlak f6444f5d35 feat(bot-slack): modernize native streaming (task chunks, feedback, single-message)
Bring the Slack adapter up to the current native streaming API surface
(chat.startStream/appendStream/stopStream, GA Oct 2025) and remove the
type-erasure workarounds.

- Remove `as unknown as Parameters<...>` casts in favor of the SDK's typed
  args (ChatStartStream/AppendStream/StopStream/PostMessage/UpdateArguments).
- Stream a whole turn into ONE message: drop the per-message continuation
  splitting (no documented cumulative cap; matches vercel/chat), keeping the
  12k per-append chunking.
- Surface tool progress as native in-message `task_update` chunks
  (task_display_mode "timeline"), degrading to `🔧` rows where
  structured chunks are unavailable.
- Add opt-in AI feedback buttons via `slack({ feedback })` — a typed
  context_actions/feedback_buttons row attached at stopStream, with clicks
  routed adapter-locally (bypassing the engine's interaction dispatch).
- Scope recipient_user_id/recipient_team_id to channel targets only.
- Lower the native flush floor to ~600ms (appendStream Tier-4), legacy stays
  800ms.

Engine: add an optional, backward-compatible RunRenderer.finish() hook called
after runAgentLoop so a turn-scoped renderer can finalize its stream.
2026-06-18 12:39:05 +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