Commit Graph

12110 Commits

Author SHA1 Message Date
Jordan Ritter 10ef8512c4 chore(voice): move @copilotkit/runtime from dependencies to peerDependencies (#5055)
## Summary

Moves `@copilotkit/runtime` from `dependencies` to `peerDependencies` in
`@copilotkit/voice`, and adds it to `devDependencies` so voice's own
typecheck/tests/build continue to work.

## Why

When voice declares runtime as a regular dependency, npm/pnpm may
install a **second copy** of `@copilotkit/runtime` nested under
`node_modules/@copilotkit/voice/node_modules/` whenever the resolved
version differs from the consumer's top-level runtime version. This
causes:

- **Type drift** — consumers importing from voice get types/classes from
the nested runtime, while their app code uses the top-level runtime.
Identity checks fail, type assertions silently degrade.
- **Singleton drift** — module-level state (caches, registries)
duplicates across the two copies.
- **Version slip** — patch updates to the top-level runtime don't
propagate to the nested copy.

As a peer dependency, voice now defers entirely to the consumer's
runtime version. The `devDependencies` entry keeps voice's own
typecheck/tests/build green.

## Consumer audit (CK monorepo)

Every package/example/showcase integration that depends on
`@copilotkit/voice` also declares a direct dependency on
`@copilotkit/runtime` — verified across all 21 consumers (19 showcase
integrations + 2 v2 examples). No consumer is broken by this move.

## Changes

- `packages/voice/package.json`: runtime moved `dependencies` →
`peerDependencies` + added to `devDependencies` (workspace:* in all
three blocks where applicable, matching the existing pin)
- `pnpm-lock.yaml`: regenerated, scoped to the voice importer block only
(3 lines moved between dependencies/devDependencies)

## Verification

- `pnpm install --lockfile-only` succeeds with clean, scoped diff
- `pnpm check-types` in voice produces **zero new errors** vs `main`
(the 2 pre-existing errors — module-resolution +
`@copilotkit/runtime/v2` typing — are unchanged baseline)
- Per-package `pnpm --filter @copilotkit/voice test` passes (1/1)

## Notes on commit hook

- Skipped `lint-fix` (oxfmt rewrites `package.json` to JSON5 syntax with
trailing commas, producing invalid JSON that breaks `pnpm install` —
pre-existing bug unrelated to this change; sibling `package.json` files
have not been touched by it)
- Skipped `test-and-check-packages` (pre-existing
`@copilotkit/web-inspector:test` failure on `main`: `TypeError:
window.localStorage.clear is not a function` — reproduced on `main`
HEAD, unrelated to voice)
2026-05-27 13:44:19 -07:00
Tyler Slaton 64ceb507fe Remove sidebar pill styling from shell-docs 2026-05-27 13:42:46 -07:00
Tyler Slaton 37db1c8e5b Fix shell-docs setup packaging and framework nav 2026-05-27 13:41:54 -07:00
Martha Kelly Schumann bcda2a11c2 Merge branch 'main' into fix/ENT-658-sdk-thread-tool-roundtrip 2026-05-27 13:19:49 -07:00
github-actions[bot] 12fc2a03f6 style: auto-fix formatting 2026-05-27 20:15:32 +00:00
Jordan Ritter df6daf55f1 chore(voice): move @copilotkit/runtime from dependencies to peerDependencies
Prevents nested-deps drift when consumers depend on @copilotkit/runtime
at a different version than voice's pinned version. Runtime is now a
peer dependency (consumer-controlled), with devDependencies retaining
the pin so voice's own tests and typecheck continue to work.
2026-05-27 13:14:08 -07:00
Jordan Ritter f8e38ee33b feat(showcase): SHOWCASE_BACKEND_HOST_PATTERN env var + manifest cleanup (#5047)
## Summary

Consolidate the per-integration Railway hostname into a single
env-var-driven host pattern, and strip the now-redundant `backend_url`
field from every integration manifest.

Originally proposed as three PRs; this branch carries the merged scope
of **PR1 + PR2**. **PR3 is moot** — `registry.json` is already
gitignored (`showcase/.gitignore` lines 18-21) and the inline
`INTEGRATIONS` array referenced by the original proposal was already
deleted in a prior PR. Nothing left to do there.

## Why

Previously every integration manifest hard-coded its Railway host
(`backend_url: https://showcase-<slug>-production.up.railway.app`). That
hostname is fully derivable from the slug, which made it impossible to
point a single deployed smoke image at a different backend environment
(staging, preview, an on-call ephemeral) without regenerating
`registry.json`. After this PR the URL is built at
`generate-registry.ts` time from `SHOWCASE_BACKEND_HOST_PATTERN` + slug,
and an override env var is the single knob.

## Changes

### Commit 1 — `feat(showcase): add SHOWCASE_BACKEND_HOST_PATTERN env
var with dual-read`

**`showcase/scripts/generate-registry.ts`**
- Reads `SHOWCASE_BACKEND_HOST_PATTERN` (default:
`showcase-{slug}-production.up.railway.app`).
- For each manifest, synthesizes `backend_url =
https://${pattern.replace("{slug}", slug)}` if the manifest does not
supply one. Manifest value wins (dual-read), which is why the synthesis
was a behavioural no-op on its own.

**`showcase/tests/e2e/integration-smoke.spec.ts`**
- Honors `SHOWCASE_BACKEND_HOST_PATTERN` at runtime so a single deployed
smoke image can be re-pointed at a different backend without
regenerating `registry.json`. `LOCAL_PORTS=1` still wins; default
behavior unchanged.

### Commit 2 — `feat(showcase): remove backend_url from manifests,
synthesize from host pattern`

**`showcase/integrations/*/manifest.yaml` (all 19)**
- Drop the redundant `backend_url:` line. `starter.demo_url` is
intentionally retained on the manifests that have one — those Railway
hostnames carry per-deploy hash suffixes that the host pattern cannot
reproduce.

**`showcase/scripts/generate-registry.ts`**
- Rebuild each manifest object so the synthesized `backend_url` slots in
immediately after `copilotkit_version`. This keeps `registry.json`
byte-identical to the pre-PR1 output even though manifests no longer
ship the key. Comment now reflects the post-PR2 state.

**`showcase/scripts/create-integration/index.ts`**
- Drop the hardcoded `backend_url:` line from the manifest template
emitted by `create-integration` so newly scaffolded integrations omit
the field too.
- No drift-detection workflow edit is needed:
`showcase_drift-detection.yml` was already replaced by
showcase-harness's `aimock_wiring` / `image-drift` probes (see the
existing comment in `create-integration/index.ts`).

**`showcase/shared/manifest.schema.json`**
- Remove `backend_url` from `required[]`.
- Update its description to mark it deprecated / synthesized at build
time. The on-save linter reformatted the file to 4-space + trailing
commas in the same hunk; the structural change is the two items above.

## Verification

- Regenerated `registry.json` after each commit; `diff` against the
baseline confirms **byte-identical** output across all four shells
(`shell`, `shell-docs`, `shell-dojo`, `shell-dashboard`).
- Override demo:
`SHOWCASE_BACKEND_HOST_PATTERN='showcase-{slug}-staging.example.com'`
regenerates per-slug staging URLs as expected; default rebuild returns
to byte-identical baseline.
- `tsc --noEmit -p showcase/scripts/tsconfig.json` — clean.
- `vitest run` in `showcase/scripts/` — **1308/1308 passing**.
- `playwright test --list` in `showcase/tests/` — 79 tests enumerate
cleanly.

## Pre-existing test failures noted

The repo's pre-commit hook runs `pnpm run test` across the whole
monorepo. On `origin/main` HEAD, `@copilotkit/web-inspector:test` fails
(Vitest/jsdom `window.localStorage.clear is not a function` in
`src/lib/__tests__/telemetry.test.ts`) and `@copilotkit/react-core:test`
is nx-flagged flaky. Both are unrelated to this PR — the original PR1 CI
on this branch is green on the parent commit. Both commits on this
branch were made with `--no-verify` for that reason.

## Test plan

- [ ] CI passes on this PR
- [ ] `npm run generate-registry` in `showcase/scripts/` produces
byte-identical output to current `main`
- [ ] `SHOWCASE_BACKEND_HOST_PATTERN=...` overrides backend URLs for
every integration (no more per-manifest opt-out, since manifests no
longer carry the field)
- [ ] Smoke spec parses + lists tests via `playwright test --list`
2026-05-27 13:12:51 -07:00
Jordan Ritter c0a2b11ec1 fix(web-inspector): shim localStorage in vitest setup for Node 25 (#5053)
## Summary

Node 25 ships an experimental built-in `localStorage` global accessor
(gated on `--localstorage-file`, but the accessor exists unconditionally
and the warning `\`--localstorage-file\` was provided without a valid
path` surfaces in test output). On Node 25, vitest's jsdom environment
ends up with `window.localStorage === globalThis.localStorage` pointing
at Node's empty stub — no `clear()`, no `setItem()`, no `removeItem()`,
no `getItem()`.

The fallout: all 22 telemetry tests in `packages/web-inspector` fail
with `TypeError: window.localStorage.clear is not a function`, and the
lefthook pre-commit hook blocks every commit repo-wide until folks pass
`--no-verify`.

## Fix

Add `packages/web-inspector/vitest.setup.ts` that installs a plain
in-memory `Storage` shim on both `globalThis` and `window` once at
module load and again in `beforeEach`. Wire it via `setupFiles` in
`vitest.config.ts`.

Plain-object shim (not a class) so `vi.spyOn(window.localStorage,
"getItem")` continues to work — vitest needs the spied methods to be own
properties on the target. `Object.defineProperty` with `configurable:
true` so we can override Node's accessor.

## Why this approach

- (a) Setup-file shim — minimal config delta, zero source/test changes,
works on both Node 20 and Node 25.
- (b) Switch to `happy-dom` — bigger blast radius, may have other
behavior diffs.
- (c) `vi.stubGlobal` per test — invasive, requires touching every test.
- (d) Disable Node's experimental `localStorage` — no stable flag
exists; can't rely on it.

We picked (a).

## Verification

- 22/22 failing telemetry tests now pass.
- Full `pnpm test` in `packages/web-inspector`: 29/29 pass (telemetry 22
+ web-inspector spec 7).
- Lefthook pre-commit ran cleanly on this branch without `--no-verify`
(test-and-check-packages 145s, commitlint OK).

## Test plan

- [x] `pnpm exec vitest run src/lib/__tests__/telemetry.test.ts` in
`packages/web-inspector` — 22/22 pass on Node 25.8.0
- [x] `pnpm test` in `packages/web-inspector` — 29/29 pass
- [x] `git commit` without `--no-verify` succeeds (lefthook pre-commit +
commit-msg both green)
- [ ] CI: web-inspector lane green
2026-05-27 13:11:57 -07:00
Jordan Ritter d61908dd1e chore(deps): bump @ag-ui/langgraph to 0.0.34
Picks up the forwarded-headers fix from ag-ui PR #1798
(https://github.com/ag-ui-protocol/ag-ui/pull/1798), which injects
agent.headers as config.configurable.copilotkit_forwarded_headers so
the LG dev server's HTTP-to-configurable bridge is no longer required
for X-AIMock-Context propagation. Closes the header-propagation gap
for showcase D5/D6 langgraph-typescript probes.
2026-05-27 12:55:30 -07:00
Martha Schumann daff12758a fix(showcase): use uuid explicit thread demo id 2026-05-27 12:53:06 -07:00
Jordan Ritter 3e0a6a0d85 fix(web-inspector): shim localStorage in vitest setup for Node 25 compatibility
Node 25 ships an experimental built-in localStorage global accessor that
shadows jsdom's mock, leaving window.localStorage as an empty stub with
no clear/setItem/removeItem/getItem methods. This broke all 22 telemetry
tests with 'window.localStorage.clear is not a function' and was
blocking pre-commit hooks repo-wide.

Add a vitest setup file that installs a proper in-memory Storage shim
on both globalThis and window before each test, so jsdom-environment
tests behave the same on Node 20 and Node 25.
2026-05-27 12:49:08 -07:00
Tyler Slaton 926a91ba12 Disable fumadocs search in shell docs 2026-05-27 12:40:34 -07:00
github-actions[bot] 7b56e31de5 style: auto-fix formatting 2026-05-27 19:38:07 +00:00
Jordan Ritter 3f120b0774 feat(showcase): remove backend_url from manifests, synthesize from host pattern
PR1 added the SHOWCASE_BACKEND_HOST_PATTERN env var and a dual-read in
generate-registry.ts that synthesizes backend_url when the manifest omits
it. This commit (PR2) makes the env-var-derived path the only path.

- Strip the now-redundant backend_url: line from all 19 integration
  manifests (showcase/integrations/*/manifest.yaml).
- generate-registry.ts: rebuild manifest objects so the synthesized
  backend_url slots in immediately after copilotkit_version. With this
  change registry.json is byte-identical to the pre-PR1 output while the
  source of truth is now the env var, not the manifests. Comment updated
  to reflect the new state.
- create-integration template: drop the hardcoded
  backend_url: https://showcase-<slug>-production.up.railway.app line so
  newly scaffolded integrations omit the field too. The drift-detection
  workflow injection mentioned in earlier PR2 drafts is gone already:
  showcase-harness's aimock_wiring / image-drift probes replaced
  showcase_drift-detection.yml, so no workflow file needs editing.
- manifest.schema.json: drop backend_url from required, update its
  description to call out the deprecation and synthesis path. The file
  was reformatted by the local linter on save (4-space + trailing commas)
  in the same hunk; the structural change is the required-list and the
  description.
- starter.demo_url is intentionally retained because Railway hostnames
  there carry per-deploy hash suffixes the host pattern can not
  reproduce.

Verified locally:
- tsx generate-registry.ts -> byte-identical to baseline registry.json.
- SHOWCASE_BACKEND_HOST_PATTERN='showcase-{slug}-staging.example.com'
  produces the expected per-slug staging URLs.
- tsc --noEmit -p showcase/scripts/tsconfig.json: clean.
- vitest run in showcase/scripts: 1308/1308 passing.
- playwright test --list in showcase/tests: 79 tests enumerate cleanly.

Pre-commit hook skipped via --no-verify: the lefthook test-and-check task
runs the whole monorepo (pnpm run test) and is flaking on
@copilotkit/web-inspector independent of this branch; PR #5047 CI on the
parent commit is already green so the lefthook failure is not caused by
PR2 changes.
2026-05-27 12:37:04 -07:00
Jordan Ritter e8e8338235 feat(showcase): add SHOWCASE_BACKEND_HOST_PATTERN env var with dual-read
PR1 of 3 toward removing repo-baked Railway hostnames from showcase
integration manifests.

generate-registry.ts now reads SHOWCASE_BACKEND_HOST_PATTERN
(default: showcase-{slug}-production.up.railway.app). For each
manifest, backend_url falls back to the synthesized value only when
the manifest omits it. Every manifest currently sets backend_url
explicitly, so the synthesized path is unreachable in production data
and the emitted registry.json is byte-identical to the previous output
(verified via diff against pre-change generation).

integration-smoke.spec.ts honors SHOWCASE_BACKEND_HOST_PATTERN at
runtime: when set, each integration's backendUrl is recomputed from the
pattern so a single deployed smoke image can be re-pointed at a
different backend environment without regenerating registry.json.
LOCAL_PORTS=1 still takes precedence. Behavior with no env var is
identical to before.

No behavior change. Forward-compatible with PR2 (drop backend_url from
manifests so the synthesis becomes the source of truth).
2026-05-27 12:24:53 -07:00
Benjamin Taylor 122b2ab000 fix(ci): pack workspace as tarball to bypass upload-artifact enumeration
upload-artifact's path filters are post-walk: even with !**/node_modules/**
exclusions, the action still descends into every node_modules and stats
every file (~6M for this monorepo with pnpm's .pnpm/ symlink farm) before
applying negations. That enumeration is the actual bottleneck — the
Upload workspace step runs 10+ minutes even with the filters added in
#5044.

Replace the filtered upload with: rm -rf the heavy dirs (node_modules,
.nx, .turbo, .next), tar the workspace into a single file, upload that.
Publish job tar -xzf's it after download and continues unchanged. Single-
file upload skips upload-artifact's per-file overhead entirely.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 13:47:20 -05:00
Ran Shemtov ca5e5614e9 Merge branch 'main' into wt-4995-29229-6154 2026-05-27 20:19:52 +02:00
Martha Kelly Schumann 2bef4ba915 Merge branch 'main' into fix/ENT-658-sdk-thread-tool-roundtrip 2026-05-27 11:05:41 -07:00
Ben Taylor ee6b2c314d fix(ci): exclude node_modules from prerelease workspace artifact (#5044)
## Summary

- The `release / pre` workflow has been failing on every run since
commit 770759a4be ("fix(ci): separate build and publish jobs in release
workflows", May 11). The `Upload workspace` step hits a JS heap OOM in
`actions/upload-artifact@v7` after enumerating 5,923,811 files.
- Root cause: the build → publish handoff uses `path: .` +
`include-hidden-files: true`, which packs the entire workspace **after
`pnpm install`** — including every `node_modules/`, every nested
`.pnpm/` store entry (symlinks materialized), `.next`, `.turbo`, `.nx`
caches, plus every `examples/*/node_modules` and showcase app subtree.
The action holds the full manifest in memory before streaming → ~4GB
heap, OOM.
- `publish-release.yml` already encountered this and was patched: it
excludes `node_modules`/`.next`/`.turbo`/`.nx` and re-runs `pnpm install
--frozen-lockfile` in the publish job. This PR ports the same pattern to
`prerelease.yml` — no novel design.

## Why this preserves the security split

The original 770759a4be change separated `build` and `publish` so
`NPM_TOKEN` is only in the publish job's process tree, preventing token
exfiltration from build-time code. That property is untouched: the
artifact still carries pre-built `dist/` directories with the
already-bumped versions, and the publish job still runs only the publish
script. The `pnpm install --frozen-lockfile` in the publish job runs
against the same `pnpm-lock.yaml` carried in the artifact —
deterministic and at the same versions the build job validated.

## Test plan

- [ ] Trigger a `release / pre` run with `--dry-run=true` against this
branch — expect `Upload workspace` to complete in seconds instead of
OOMing after 11 minutes.
- [ ] Verify the `Publish prerelease` step still finds `tsx` and `pnpm
pack` works (i.e. the added `Install Dependencies` step restores
node_modules correctly).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-27 13:05:23 -05:00
Benjamin Taylor 7cf05df90e fix(ci): exclude node_modules from prerelease workspace artifact
The prerelease workflow has been OOMing on Upload workspace since the
build/publish split in 770759a4be. The artifact upload enumerates
~6M files (root + per-package node_modules with pnpm symlinks all
materialized, plus build caches) and actions/upload-artifact builds
the full manifest in memory before streaming, blowing past the 4GB
Node heap limit.

publish-release.yml already had the working pattern: exclude
node_modules/.next/.turbo/.nx and re-run pnpm install --frozen-lockfile
in the publish job. Port it over so prerelease publishes succeed
again.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 13:02:15 -05:00
Martha Kelly Schumann 25455c522c Merge branch 'main' into fix/ENT-658-sdk-thread-tool-roundtrip 2026-05-27 10:58:01 -07:00
Tyler Slaton 5e4af9e017 feat(docs): improve search design and sidebar layout (#5034)
## Summary
- Reworked the search modal into a clearer docs-scoped search experience
with a visible "Searching docs for" framework selector
- Removed demo results from search and improved framework-specific
deduping for docs content
- Tightened the homepage and header chrome spacing to better fit the
updated shell-docs theme
- Ensured the CopilotKit kite mark is used consistently for the built-in
agent selector

## Testing
- `npm run typecheck` passed
- `npm run lint` passed with existing repository warnings only
- Verified the updated search modal and selector behavior in the local
browser
2026-05-27 10:57:41 -07:00
Martha Kelly Schumann 7afdd166ce Merge branch 'main' into fix/ENT-658-sdk-thread-tool-roundtrip 2026-05-27 10:57:24 -07:00
Martha Schumann a879b8a062 test(react-core): tighten thread roundtrip coverage 2026-05-27 10:49:20 -07:00
Ben Taylor f02b83c348 fix(react-core): propagate threadId prop from CopilotKit to agent (#5041) (#5042)
## Summary

- Wires `useAgent` to sync `agent.threadId` from
`CopilotChatConfigurationProvider` when the caller marked the threadId
as explicit. AbstractAgent's constructor was auto-minting a UUID, so
`ProxiedCopilotRuntimeAgent` was shipping that random UUID in
`/agent/run`, `/agent/connect`, `/agent/stop` instead of the value the
caller passed via `<CopilotKit threadId={x}>` — breaking thread
persistence and causing 404s on lookup.
- Fixes #5041 (V1 `<CopilotChat>` path) and #4739 (headless `useAgent`
path), which share the same root cause.

## Why this regressed

PR #3525 originally solved this with per-thread agent cloning. That
cloning was reverted in commit `762370a4e5` (May 2026) because it wiped
state on tool calls. The revert restored the explicit `agent.threadId =
resolvedThreadId` assignment only in the V2 `CopilotChat` component —
the V1 chat hook (`use-copilot-chat_internal.ts`) and headless
`useAgent` paths were left without an equivalent sync.
`use-agent-thread-isolation.test.tsx` (333 lines) was deleted in the
revert and never replaced for those surfaces, which is why this
regressed silently.

The fix lives in `useAgent` rather than the V1 chat hook because V1 chat
already routes through `useAgent` for agent acquisition, and a headless
`useAgent` user (issue #4739) gets the sync for free. The gate on
`hasExplicitThreadId` matches V2 `CopilotChat`'s gating so a
`ThreadsProvider`-minted placeholder doesn't overwrite the agent's
auto-minted UUID before a real thread exists.

## Test plan

- [x] 4 new unit tests in `use-agent-threadid-sync.test.tsx` covering:
explicit sync, the non-explicit no-op path, threadId change re-sync, and
the no-provider headless case.
- [x] 2 new integration tests in `v1-explicit-threadid-bridge.test.tsx`
covering the customer's exact scenario: `<CopilotKit threadId={x}>` →
`useAgent` → `agent.threadId === x`.
- [x] All 1177 existing `@copilotkit/react-core` tests still pass.
- [x] `@copilotkit/react-core:build` succeeds.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-27 12:33:20 -05:00
Martha Schumann 24d93b52ad fix(react-core): preserve generated thread tool followups 2026-05-27 10:27:29 -07:00
Benjamin Taylor eddff6d6ee test(react-core): move threadId-propagation test out of the hooks dir
The previous regression (#5041, shared root cause with #4739) slipped through
because the original coverage (use-agent-thread-isolation.test.tsx) lived
next to the per-thread-cloning feature and was deleted alongside it when
cloning was reverted. The invariant outlived the feature but the tests didn't.

Relocate to packages/react-core/src/__tests__/ and rename as a contract test
so future implementation swaps (cloning, effect, prop drilling, context) keep
it in scope. Tightened the header docstring to spell out the invariant and the
reason for the placement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 12:19:30 -05:00
Benjamin Taylor d1506ec66c fix(react-core): propagate threadId prop from CopilotKit to agent (#5041)
useAgent now syncs agent.threadId from CopilotChatConfigurationProvider when
the caller marked the threadId as explicit. Without this, AbstractAgent's
constructor mints a random UUID and ProxiedCopilotRuntimeAgent ships it in
/agent/run, /agent/connect, /agent/stop — diverging from the threadId app code
reads via useThreads, breaking thread persistence and causing 404s on lookup.

This was originally fixed by per-thread agent cloning in #3525. That cloning
was reverted in May 2026 because it wiped state on tool calls, and the revert
only restored the explicit assignment in V2 CopilotChat — leaving headless
useAgent (issue #4739) and the V1 chat hook path unfixed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 12:06:46 -05:00
Tyler Slaton ac25cc3523 Merge branch 'main' into tyler/showcase-improve-docs-design 2026-05-27 09:51:24 -07:00
Austin Merrick d0d3b64aac docs(shell-docs): add CopilotKit Skills section to build-with-agents page (#5039)
## Summary

Adds the Skills installation section to the shell-docs
`/build-with-agents` page

## Changes


**`showcase/shell-docs/src/content/snippets/shared/guides/build-with-agents.mdx`**
(new)
- Single source of truth for the page content
- Intro paragraph, `## CopilotKit Skills` section (Callout + Steps:
install + starter prompt), `<MCPSetup />` as second section

**`showcase/shell-docs/src/content/docs/build-with-agents.mdx`**
- Replaced inline content with `<BuildWithAgents />` — delegates to the
shared snippet
- Icon updated to `BrainCircuit`, description updated to keyword-rich
copy, `hideTOC: true` removed


**`showcase/shell-docs/src/content/docs/integrations/built-in-agent/build-with-agents.mdx`**
- Replaced `<SharedContent />` with `<BuildWithAgents />` so the skills
section appears here too (built-in-agent uses `docs_mode: authored` and
never falls through to the root page)


**`showcase/shell-docs/src/content/snippets/shared/guides/mcp-server-setup.mdx`**
- `## Overview` → `## MCP Docs Server`

**`showcase/shell-docs/src/lib/docs-render.tsx`** +
**`mdx-registry.tsx`**
- Register `BuildWithAgents` in `SNIPPET_MAP` and component registry

## Acceptance criteria status

- [x] `/coding-agents` redirects to `/build-with-agents` (PR #5023)
- [x] React Native moved to Platforms section (PR #4927 / #5023)
- [x] `npx skills add` flow documented with skills link and starter
prompt
- [x] MCP server install instructions present (existing content, now
labeled correctly)
- [x] Page structure follows Mastra "Build with AI" reference
2026-05-27 09:38:18 -07:00
Austin Merrick bfbd074cc2 fix(skills): mark showcase-demo-debugging as internal (#5040)
## Summary

Adds `metadata.internal: true` to
`.claude/skills/showcase-demo-debugging/SKILL.md` so it is hidden from
`npx skills add CopilotKit/CopilotKit` public installs.

## Why

`showcase-demo-debugging` is a contributor-only skill (for working on
showcase demos, fixtures, and CI regressions). It has no value to a user
building a CopilotKit app, but was showing up in the install summary.
This brings it in line with `git-hooks` and `copilotkit-demo-parity`
which were fixed the same way in PR #4937.

## Change

```yaml
metadata:
  internal: true
```

One field, same pattern as #4937.
2026-05-27 09:38:09 -07:00
Austin Merrick 94f473b284 refactor(shell-docs): single source of truth for build-with-agents content
Root page was duplicating the snippet content inline. Switch it to
<BuildWithAgents /> so snippets/shared/guides/build-with-agents.mdx
is the one source — root page and built-in-agent both render from it.
2026-05-27 09:13:46 -07:00
Austin Merrick 7b14a8c982 fix(shell-docs): fix build-with-agents on built-in-agent (authored mode)
built-in-agent uses docs_mode: 'authored' so it loads the per-framework
integrations/built-in-agent/build-with-agents.mdx directly, bypassing
the root page entirely. Other frameworks (generated mode) fall through
to the root page and already show the skills section.

Fix: extract the full page body into a shared snippet
  snippets/shared/guides/build-with-agents.mdx
register it as <BuildWithAgents /> in SNIPPET_MAP + mdx-registry, and
switch built-in-agent's page to <BuildWithAgents />. Root page keeps
its inline content (for crawlability). The snippet is the source used
by authored-mode frameworks; root is the source for generated-mode and
crawlers — same pattern as MCPSetup / coding-agents.
2026-05-27 09:06:45 -07:00
Austin Merrick b9514a9037 fix(skills): mark showcase-demo-debugging as internal
Add `metadata.internal: true` so the skill is hidden from
`npx skills add CopilotKit/CopilotKit` public installs.
Same pattern as PR #4937 for git-hooks and copilotkit-demo-parity.
2026-05-27 08:47:13 -07:00
Austin Merrick 3f8d2de8a6 docs(shell-docs): remove skills table, replace with prose + link
The table was incomplete (6 skills listed, 12 actually install) and has
no CI check to keep it in sync. Replace with a one-line prose summary
and a link to the canonical skills/ directory on GitHub, which is always
accurate.
2026-05-27 08:44:56 -07:00
Ran Shemtov 9158241c10 Merge branch 'main' into wt-4995-29229-6154 2026-05-27 17:39:28 +02:00
Austin Merrick 6b1747e5f8 docs(shell-docs): add CopilotKit Skills section to build-with-agents page
- Rewrites the root build-with-agents page to document Skills + MCP Docs Server
- Skills section: intro, npx skills add command, skills table, starter prompt
- Removes hideTOC so the new TOC (Skills / MCP Docs Server) renders
- Updates icon to BrainCircuit and description to keyword-rich copy
- Renames mcp-server-setup snippet heading: ## Overview → ## MCP Docs Server
  so both sections compose cleanly on the root page without a double Overview

Closes out the last AC on OSS-133: npx skills add flow documented with
table of skills, starter prompt, and page structure matching Mastra reference.
2026-05-27 08:30:56 -07:00
Maxim ca7ed4246a feat(sdk): add optional id parameter to copilotkit_emit_tool_call (#4923)
## Summary
- Adds an optional `tool_call_id` / `toolCallId` parameter to
`copilotkit_emit_tool_call` across all three SDK variants (Python
LangGraph, Python CrewAI, JS/TS)
- When provided, the custom ID is used as the `toolCallId` in AG-UI
protocol events; when omitted, a random UUID is generated (backwards
compatible)
- All variants now return the tool call ID (`str` / `Promise<string>`)
instead of `True` / `void`, aligning the LangGraph Python and JS
variants with CrewAI which already returned it
- Introduces `CopilotKitError` base exception class and
`CopilotKitMisuseError` for invalid API usage in the Python SDK
- Adds compensating `TOOL_CALL_END` / `action_execution_end` dispatch
when mid-stream failures occur, preventing stuck client UIs
- Exports all exception types from the `copilotkit` package root

## Motivation
Customer request — enables use cases including:
- **Correlation across agent steps** — emit a tool call with a known ID
and reference it later
- **Idempotency / replay safety** — deterministic IDs prevent duplicate
tool calls on LangGraph checkpoint replays
- **External system linking** — use a job ID, trace span ID, or request
correlation ID as the tool call ID
- **Custom HITL flows** — programmatically approve/reject a specific
tool call by predictable ID
- **Testing** — deterministic IDs make snapshot/integration tests stable

## Behavioral changes
- **JS dispatch errors are no longer wrapped in
`CopilotKitMisuseError`**: Previously, `copilotkitEmitToolCall` wrapped
any `dispatchCustomEvent` failure in a `CopilotKitMisuseError`.
Transport/dispatch errors now propagate as their native error types.
This is more correct — a dispatch failure is not a misuse error — but
callers that specifically caught `CopilotKitMisuseError` for transport
errors will need to update their catch clauses.
- **Python return type changed**: `copilotkit_emit_tool_call` previously
returned `True` (documented as `Awaitable[bool]`). It now returns `str`
(the tool call ID). Code using truthiness checks (`if result:`) is
unaffected; strict equality (`== True`) will break.

## Test plan
- [x] 4 unit tests for LangGraph Python variant (default UUID, custom
ID, return value, explicit None)
- [x] 3 unit tests for CrewAI Python variant (skipped when crewai not
installed)
- [x] 3 integration tests for AG-UI dispatch (custom ID propagates to
all TOOL_CALL events)
- [x] All 26 existing `test_agui_agent.py` tests pass (no regressions)
- [x] JS SDK builds cleanly (`nx run @copilotkit/sdk-js:build`)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-27 15:12:20 +02:00
Maxim dff634d462 Merge branch 'main' into feature/emit-tool-call-optional-id 2026-05-27 15:12:10 +02:00
github-actions[bot] a1f5512155 chore(ci)(deps): bump the minor-and-patch group with 2 updates (#5037)
Bumps the minor-and-patch group with 2 updates:
[docker/login-action](https://github.com/docker/login-action) and
[depot/build-push-action](https://github.com/depot/build-push-action).

Updates `docker/login-action` from 4.1.0 to 4.2.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/login-action/releases">docker/login-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.2.0</h2>
<ul>
<li>Bump <code>@​actions/core</code> from 3.0.0 to 3.0.1 in <a
href="https://redirect.github.com/docker/login-action/pull/976">docker/login-action#976</a></li>
<li>Bump <code>@​aws-sdk/client-ecr</code> and
<code>@​aws-sdk/client-ecr-public</code> to 3.1050.0 in <a
href="https://redirect.github.com/docker/login-action/pull/960">docker/login-action#960</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.86.0 to 0.90.0 in
<a
href="https://redirect.github.com/docker/login-action/pull/970">docker/login-action#970</a></li>
<li>Bump brace-expansion from 2.0.1 to 5.0.6 in <a
href="https://redirect.github.com/docker/login-action/pull/993">docker/login-action#993</a></li>
<li>Bump fast-xml-builder from 1.1.4 to 1.2.0 in <a
href="https://redirect.github.com/docker/login-action/pull/985">docker/login-action#985</a></li>
<li>Bump fast-xml-parser from 5.3.6 to 5.8.0 in <a
href="https://redirect.github.com/docker/login-action/pull/963">docker/login-action#963</a></li>
<li>Bump http-proxy-agent and https-proxy-agent to 9.0.0 in <a
href="https://redirect.github.com/docker/login-action/pull/961">docker/login-action#961</a></li>
<li>Bump postcss from 8.5.6 to 8.5.10 in <a
href="https://redirect.github.com/docker/login-action/pull/979">docker/login-action#979</a></li>
<li>Bump tar from 6.2.1 to 7.5.15 in <a
href="https://redirect.github.com/docker/login-action/pull/991">docker/login-action#991</a></li>
<li>Bump vite from 7.3.1 to 7.3.3 in <a
href="https://redirect.github.com/docker/login-action/pull/986">docker/login-action#986</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/login-action/compare/v4.1.0...v4.2.0">https://github.com/docker/login-action/compare/v4.1.0...v4.2.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/login-action/commit/650006c6eb7dba73a995cc03b0b2d7f5ca915bee"><code>650006c</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/960">#960</a>
from docker/dependabot/npm_and_yarn/aws-sdk-dependenc...</li>
<li><a
href="https://github.com/docker/login-action/commit/99df1a3f6d65e48177ea57671a50e2242eae4b63"><code>99df1a3</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/login-action/commit/3ab375f324f46da5f6901efeda4be4e2566ebaa2"><code>3ab375f</code></a>
build(deps): bump the aws-sdk-dependencies group across 1 directory with
2 up...</li>
<li><a
href="https://github.com/docker/login-action/commit/39d85804ae465a1816c68ff58158ec66883981b4"><code>39d8580</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/970">#970</a>
from docker/dependabot/npm_and_yarn/docker/actions-to...</li>
<li><a
href="https://github.com/docker/login-action/commit/4eefcd33ca7213989697445a78b6730274bfaba6"><code>4eefcd3</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/login-action/commit/56d092c8b3f04006c22f4fc20a2b3d2442caed56"><code>56d092c</code></a>
build(deps): bump <code>@​docker/actions-toolkit</code> from 0.86.0 to
0.90.0</li>
<li><a
href="https://github.com/docker/login-action/commit/e2e31ca87063ae00fd41ad3b9c548dd8ec24c5ff"><code>e2e31ca</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/976">#976</a>
from docker/dependabot/npm_and_yarn/actions/core-3.0.1</li>
<li><a
href="https://github.com/docker/login-action/commit/0bced941e843afc786fbfd58b1c6c13ca11e09c9"><code>0bced94</code></a>
chore: update generated content</li>
<li><a
href="https://github.com/docker/login-action/commit/3e75a0f266b07e09777a621d0ca5f4432ef9f10c"><code>3e75a0f</code></a>
build(deps): bump <code>@​actions/core</code> from 3.0.0 to 3.0.1</li>
<li><a
href="https://github.com/docker/login-action/commit/365bebd9d646160567ebad47824f026e09ee6970"><code>365bebd</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/login-action/issues/984">#984</a>
from docker/dependabot/github_actions/aws-actions/con...</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/login-action/compare/4907a6ddec9925e35a0a9e82d7399ccc52663121...650006c6eb7dba73a995cc03b0b2d7f5ca915bee">compare
view</a></li>
</ul>
</details>
<br />

Updates `depot/build-push-action` from 1.17.0 to 1.18.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/depot/build-push-action/releases">depot/build-push-action's
releases</a>.</em></p>
<blockquote>
<h2>v1.18.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Upgrade action runtime to Node 24 (<a
href="https://redirect.github.com/depot/build-push-action/issues/48">#48</a>)
<a href="https://github.com/Akatama"><code>@​Akatama</code></a></li>
<li>Add Depot Registry save example (<a
href="https://redirect.github.com/depot/build-push-action/issues/47">#47</a>)
<a href="https://github.com/maschwenk"><code>@​maschwenk</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/depot/build-push-action/commit/98e78adca7817480b8185f474a400b451d74e287"><code>98e78ad</code></a>
Merge pull request <a
href="https://redirect.github.com/depot/build-push-action/issues/48">#48</a>
from depot/upgrade-node-24-runtime</li>
<li><a
href="https://github.com/depot/build-push-action/commit/e97ebff18729ac91be067461138674a006ab9bff"><code>e97ebff</code></a>
Remove Node 24 compatibility docs</li>
<li><a
href="https://github.com/depot/build-push-action/commit/2db929fa768ebb3ad332ae8fc530412bf0964782"><code>2db929f</code></a>
Upgrade action runtime to Node 24</li>
<li><a
href="https://github.com/depot/build-push-action/commit/f78af826a1c272c4b60c485e934974b515094928"><code>f78af82</code></a>
Merge pull request <a
href="https://redirect.github.com/depot/build-push-action/issues/47">#47</a>
from maschwenk/maschwenk/add-depot-registry-example</li>
<li><a
href="https://github.com/depot/build-push-action/commit/6855818d5954fa4361879bb0b0e5c32856fc6703"><code>6855818</code></a>
Update action.yml</li>
<li><a
href="https://github.com/depot/build-push-action/commit/b984f6a1944d5420eefb2b012d6eb856249bd225"><code>b984f6a</code></a>
Clarify save/save-tag/save-tags input descriptions</li>
<li><a
href="https://github.com/depot/build-push-action/commit/1a34abd3707433f4f7b6d594e49e56b4b9f4d6d0"><code>1a34abd</code></a>
Add Depot Registry save example</li>
<li>See full diff in <a
href="https://github.com/depot/build-push-action/compare/5f3b3c2e5a00f0093de47f657aeaefcedff27d18...98e78adca7817480b8185f474a400b451d74e287">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>
2026-05-27 06:27:40 +00:00
dependabot[bot] f12cbc7acd chore(ci)(deps): bump the minor-and-patch group with 2 updates
Bumps the minor-and-patch group with 2 updates: [docker/login-action](https://github.com/docker/login-action) and [depot/build-push-action](https://github.com/depot/build-push-action).


Updates `docker/login-action` from 4.1.0 to 4.2.0
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/4907a6ddec9925e35a0a9e82d7399ccc52663121...650006c6eb7dba73a995cc03b0b2d7f5ca915bee)

Updates `depot/build-push-action` from 1.17.0 to 1.18.0
- [Release notes](https://github.com/depot/build-push-action/releases)
- [Commits](https://github.com/depot/build-push-action/compare/5f3b3c2e5a00f0093de47f657aeaefcedff27d18...98e78adca7817480b8185f474a400b451d74e287)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: depot/build-push-action
  dependency-version: 1.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-27 06:27:26 +00:00
ryker 8e5901133c fix(python): serialize AGUI agent metadata safely 2026-05-27 14:10:12 +08:00
Tyler Slaton c1874ed64c Refresh shell docs homepage and search modal 2026-05-26 22:20:02 -07:00
Jordan Ritter 5d1949f532 chore(showcase): pin depot/build-push-action comment to v1.17.0
Zizmor's ref-version-mismatch audit flags the existing `# v1` comment
because the hash 5f3b3c2e5a00f0093de47f657aeaefcedff27d18 is the
v1.17.0 tag, not the v1 head. Update the trailing comment to match.

No behavior change — the SHA pin is what governs which commit Actions
fetches. This just keeps zizmor green so unrelated showcase-wiring PRs
don't trip on a pre-existing pin annotation.
2026-05-26 17:20:13 -07:00
Jordan Ritter 8a22da0f7b chore(showcase): mirror ms-agent-harness-dotnet wiring into sibling workflows
Three companion workflows duplicate the showcase_build.yml service registry
and were missed in the initial wiring commit. Bring them in sync:

- .github/workflows/showcase_build_check.yml: add ms_agent_harness_dotnet
  to the paths-filter and the ALL_SERVICES matrix (mirror of the
  production build matrix, used for pre-merge Docker build verification).
- .github/workflows/showcase_deploy.yml: add ms-agent-harness-dotnet to
  the workflow_dispatch options and the verification ALL_SERVICES with
  railway_id 6343d7f9-6c3f-4c8d-9a6e-79f03d2f1e37 and /api/health.
- .github/workflows/showcase_keep-alive.yml: add ms-agent-harness-dotnet
  to the keep-alive ping matrix.
2026-05-26 17:20:13 -07:00
Jordan Ritter e248b0edfd chore(showcase): wire ms-agent-harness-dotnet for deployment
Brings the Microsoft Agent Harness (.NET) integration live on the
showcase Railway project. Integration code itself landed in PR #4982.

Changes:
- Railway service `showcase-ms-agent-harness-dotnet` created
  (id 6343d7f9-6c3f-4c8d-9a6e-79f03d2f1e37) with the public domain
  showcase-ms-agent-harness-dotnet-production.up.railway.app, image
  source ghcr.io/copilotkit/showcase-ms-agent-harness-dotnet:latest,
  healthcheck /api/health, and env vars cloned from the sibling
  showcase-ms-agent-dotnet service.
- .github/workflows/showcase_build.yml: add ms-agent-harness-dotnet to
  workflow_dispatch options, paths-filter, and the ALL_SERVICES matrix
  (mirroring the ms-agent-dotnet sibling entry).
- showcase/integrations/ms-agent-harness-dotnet/manifest.yaml: flip
  deployed: false -> true so the dashboard surfaces the integration
  once the image is live.

Skips test-and-check-packages pre-commit hook locally because
@copilotkit/web-inspector:test has a pre-existing failure on main
(window.localStorage.clear telemetry test setup) unrelated to these
YAML-only changes.
2026-05-26 17:20:13 -07:00
Maxim 30af72749d feat(dojo): scope Controlled Generative UI to LGP + ADK Featured (OSS-137)
gen-ui-tool-based was in the global FEATURED_DEMO_IDS, so it was promoted
into Featured for all 18 integrations. The Controlled Generative UI product
treatment (reliable sample-data rendering + the "Controlled Generative UI"
pill) is only polished for LangGraph Python and Google ADK so far, so move it
out of the global list and into EXTRA_FEATURED_BY_INTEGRATION for those two,
mirroring the per-integration scoping pattern from #4980 (HITL demos).

The other 16 integrations still expose the demo in its category section; it
just isn't promoted into Featured until the treatment scales to them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 01:05:10 +02:00
github-actions[bot] 3196671575 style: auto-fix formatting 2026-05-26 22:52:00 +00:00
Maxim 478039786c fix(showcase): controlled gen-UI — reliable 2nd-suggestion render + sidebar tag (OSS-137)
The "Traffic pie chart" suggestion ("Show me a pie chart of website traffic
by source.") names a subject but supplies no numbers, so the agent asked the
user for data instead of rendering. Add a system-prompt directive (LGP + ADK)
telling the agent to invent illustrative sample values and render on the first
turn, never asking for data. The suggestion copy stays clean — the behavior is
carried by the system prompt, not parenthetical UI hints.

Also retag the gen-ui-tool-based demo (LGP + ADK) from `generative-ui` to
`controlled-generative-ui` so the dojo sidebar pill reads "Controlled
Generative UI" — the established product taxonomy (already a category in
shared/feature-registry.json and the dashboard catalog).

Scoped to LGP and ADK per the ticket; the other 16 integrations keep the old
tag until the taxonomy rolls out wider.

Tests: add D5 aimock fixture entries mirroring all three suggestion chips
(bar/traffic-pie/market-share) so the suggestion-click path has deterministic
coverage. The existing "revenue by category" probe message is preserved, so
the dashboard D5 row stays green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 00:40:37 +02:00
Mark 3a08fe2b13 fix: two-arg z.record for Zod 4 compatibility in MCP Apps schemas (#5025)
## Summary

`MCPAppsActivityContentSchema` (and a couple of sibling schemas) used
the single-argument `z.record(valueType)` form for `toolInput`. **Zod 4
made the key schema mandatory**, so the single-arg form is a
**compile-time error (`TS2554: Expected 2-3 arguments, but got 1`)**
when built against Zod 4. Since `@copilotkit/react-core` declares `zod:
">=3.0.0"`, a downstream consumer that resolves Zod 4 is affected. Fixes
#4295.

This PR switches to the two-argument `z.record(z.string(), z.unknown())`
form (valid and identical under both Zod 3 and Zod 4) and adds a lint
guard so it can't regress.

### Note on the issue's framing
The original issue (and the Linear ticket) described this as breaking
*runtime validation for non-empty records*. I verified against real Zod
4.4.3 in isolation: **runtime `safeParse` is unaffected** under both Zod
majors — the incompatibility is purely **type-level** (`tsc`). That
distinction drove the test/lint decisions below.

## Changes
- **Schemas** — `toolInput` now uses `z.record(z.string(), z.unknown())`
in:
  - `packages/react-core/.../MCPAppsActivityRenderer.tsx`
  - `packages/vue/.../MCPAppsActivityRenderer.ts`
- **Sibling fix** — same single-arg form corrected in
`packages/react-core/.../defineToolCallRenderer.test.tsx` (a `metadata`
schema).
- **Field-contract test** — added to
`MCPAppsActivityRenderer.e2e.test.tsx`, asserting `toolInput`
round-trips mixed value types. (Honest scope: a runtime test cannot
reproduce a type-level break under either Zod major — see below.)
- **Lint guard** — new `copilotkit/no-single-arg-zod-record` oxlint rule
(with autofix) in the existing `packages/react-ui/oxlint-rules/` plugin,
enabled as `error` for `packages/**` in `.oxlintrc.json`. Because the
break is type-level and the workspace lockfile pins Zod 3, this static
rule is the only thing that actually prevents regressions here.

### Lint rule scope
Scoped to `packages/**` (published surface that declares Zod
4-compatible peers). `examples/` and `showcase/` still contain the
single-arg form in ~80 spots, but those are unpublished apps with pinned
Zod; migrating them is out of scope for this fix and would be a large
mechanical change. `packages/**` is clean after this PR (0 lint errors).

## Test plan
- [x] `nx run @copilotkit/react-core:test` — affected files pass (28/28
incl. new test)
- [x] Full `packages/**` suite + `publint`/`attw` green (pre-commit
hook)
- [x] `oxlint packages/` — 0 errors; new rule fires + autofixes on a
probe, clean on the fixed code
- [x] Isolated Zod 4.4.3 repro confirms: single-arg → `TS2554`; two-arg
→ compiles; runtime parsing unaffected for both

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-26 15:35:55 -07:00