Commit Graph

296 Commits

Author SHA1 Message Date
Tyler Slaton 7158bb9576 Merge remote-tracking branch 'origin/main' into codex/shell-docs-polish-pass 2026-05-29 09:48:58 -07:00
BenTaylorDev 28f6264dd4 chore: release monorepo v1.59.1 2026-05-29 15:19:08 +00:00
Tyler Slaton 8e59b1e2e9 chore: run pnpm format
Signed-off-by: Tyler Slaton <tyler@copilotkit.ai>
2026-05-29 08:17:21 -07:00
Martha Kelly Schumann d60285c337 fix(react-core): preserve generated thread tool followups (#5043)
## Summary
- keep `CopilotChat` agents aligned to SDK-generated thread IDs even
when `/connect` is intentionally skipped for non-explicit threads
- stabilize `CopilotKitProvider` default object props so rerenders do
not re-sync an empty local agent registry and replace the live
remote/Intelligence agent mid-run
- add regression coverage for SDK-generated thread frontend-tool
follow-up runs and provider empty-agent rerender stability
- add a focused langgraph-python showcase demo, aimock fixture,
Playwright smoke, and QA checklist for ENT-658
- add a patch changeset for `@copilotkit/react-core`

## Testing
- `npx nx run @copilotkit/react-core:test --
src/v2/components/chat/__tests__/CopilotChat.absentThreadConnect.test.tsx`
- `npx nx run @copilotkit/react-core:test --
src/v2/providers/__tests__/CopilotKitProvider.stability.test.tsx`
- Pre-commit hook passed: `pnpm run test` and `pnpm run check:packages`
- Verified exact `CopilotKit/Intelligence` repro branch
`mme/threadid-repro`: unchecked `Explicit threadId`, sent `invoke
testFrontendToolCalling with label X`, confirmed user message/tool
card/assistant reply remain visible
- Verified the same Intelligence repro with `Explicit threadId` checked
- `pnpm exec playwright test
tests/e2e/threadid-frontend-tool-roundtrip.spec.ts --project=chromium
--workers=1` from `showcase/integrations/langgraph-python`

## QA Checklist
- [x] Reproduce the reset in `CopilotKit/Intelligence` branch
`mme/threadid-repro` with `Explicit threadId` unchecked
- [x] Confirm generated-thread frontend-tool round-trip preserves the
user message, tool card, and assistant response
- [x] Confirm explicit-thread frontend-tool round-trip still preserves
the user message, tool card, and assistant response
- [x] Open `/demos/threadid-frontend-tool-roundtrip` in the
langgraph-python showcase demo
- [x] Confirm `Explicit threadId` is unchecked and the chat starts in
SDK-generated thread mode
- [x] Send `invoke testFrontendToolCalling with label X`
- [x] Confirm the user message remains visible
- [x] Confirm the `testFrontendToolCalling` card remains visible and
shows `label: X` plus `result: handled X`
- [x] Confirm the assistant reply `Frontend tool finished for X.`
appears
- [x] Confirm the chat does not return to the empty state
- [x] Repeat with `Explicit threadId` checked and confirm the
explicit-thread path is unchanged

## Notes
The visible reset had two frontend-side causes. First, the chat and
agent could diverge when the SDK generated the thread ID. Second, in
Intelligence mode, provider rerenders could re-sync an empty local agent
registry and replace the live remote agent instance mid-run, dropping
the in-memory chat stream. Both fixes live in `@copilotkit/react-core`.

The Playwright file is intentionally a smoke test for the demo
route/toggle. The source-level regressions live in
`CopilotChat.absentThreadConnect.test.tsx` and
`CopilotKitProvider.stability.test.tsx`.
2026-05-29 07:50:01 -07:00
Martha Schumann 8b62c97f60 fix(react-core): harden thread stability regression 2026-05-28 14:15:07 -07:00
Martha Schumann b54eb3a5da fix(react-core): stabilize provider defaults 2026-05-28 13:57:43 -07:00
BenTaylorDev 94b1f61cc3 chore: release monorepo v1.59.0 2026-05-27 22:31:30 +00: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
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
Mark Fogle 70f54a8403 fix: use two-argument z.record for Zod 4 compatibility, add lint guard
Zod 4 made the key schema mandatory for z.record, so the single-argument
z.record(valueType) form is a compile-time error (TS2554) when built against
Zod 4. @copilotkit/react-core declares zod ">=3.0.0", so downstream apps on
Zod 4 are affected; runtime parsing is unaffected under both majors.

- react-core + vue MCPAppsActivityContentSchema: toolInput now uses the
  two-argument z.record(z.string(), z.unknown()) form
- react-core defineToolCallRenderer test: same fix for a metadata schema
- add a toolInput field-contract test (round-trips mixed value types)
- add copilotkit/no-single-arg-zod-record oxlint rule (autofix), enabled as
  error for packages/**; the incompatibility is type-level, so no runtime
  test can guard it while the workspace lockfile pins Zod 3

Closes #4295

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 21:33:55 +00:00
BenTaylorDev ebc09ea5c0 chore: release monorepo v1.58.0 2026-05-26 15:40:57 +00:00
Sam Julien 33f669ba7b fix(packages): canonicalize docs.copilotkit.ai URLs in user-facing messages
Replace docs URLs that currently 301 through the legacy redirect catalog
with their canonical post-cutover destinations so users clicking links
from console warnings, JSDoc, and in-product help land in one hop.

URLs updated:
- /premium#how-do-i-get-access-to-premium-features
  -> /premium/overview#getting-access
- /coagents/quickstart/langgraph -> /langgraph-python/quickstart
- /coagents/shared-state/predictive-state-updates
  -> /langgraph-python/shared-state/predictive-state-updates
- /reference/v1/hooks/useCopilotChatHeadless_c
  -> /reference/v2/hooks/useCopilotChatHeadless_c
- /coagents/troubleshooting/common-issues
  -> /langgraph-python/troubleshooting/common-issues
- /quickstart#get-a-copilot-cloud-public-api-key
  -> /built-in-agent/quickstart#create-a-free-account
- /premium -> /premium/overview

URLs left as-is because they already resolve 200 with no redirect:
/migration-guides/migrate-attachments, /migration/render-message,
/telemetry.

Hook bypassed: pre-commit test failed in @copilotkit/web-inspector due
to missing jsdom dependency in its package.json (unrelated to this
change; no overlap with edited files or URLs). Tests for the four
affected packages (react-core, react-ui, shared, runtime) pass.
2026-05-22 16:37:21 -07:00
tylerslaton 938803e6f4 chore: release monorepo v1.57.4 2026-05-21 14:25:58 +00:00
Alem Tuzlak 65928b9ca3 Merge remote-tracking branch 'origin/main' into worktree-lucky-popping-wren
# Conflicts:
#	package.json
2026-05-20 10:54:04 +02:00
tylerslaton efae3dfb5b chore: release monorepo v1.57.3 2026-05-19 15:59:44 +00:00
Claude ce3084700c fix(release): swallow tanstack/virtual rAF teardown error in perf test
The release-PR workflow's pre-commit hook ran the full test suite and
failed because @tanstack/virtual-core 3.13.18 has a latent bug — its
scrollToIndex schedules a nested rAF that calls
`this.targetWindow.requestAnimationFrame(verify)` with no null-check.
The virtualizer's cleanup nulls `targetWindow` on React unmount, so the
queued rAF fires post-unmount and throws. All 1170 tests passed, but
vitest exited non-zero from the unhandled error.

Wrap rAF on both globalThis and window (separate bindings in
vitest+jsdom; tanstack uses `targetWindow.rAF` which resolves to
`window.rAF`) so callbacks hitting this specific error are swallowed.

Also fix the lint-fix lefthook command — `[ -n "{staged_files}" ]`
broke on multi-file expansion ("[: <path>: unexpected operator")
because lefthook interpolates files as space-separated words, not a
quoted string. Use `set --` to put them in positional args.
2026-05-19 15:28:07 +00:00
Austin Merrick 784b365d4f feat(react-core): forward followUp option through useComponent 2026-05-18 10:53:20 -07:00
Tyler Slaton cf0b032d58 chore: release monorepo v1.57.2 (#4787)
## Release monorepo v1.57.2

**Scope:** `monorepo` | **Bump:** `patch`

---

### How this release process works

1. **This PR was created automatically** by the "release / create-pr"
workflow.
   It bumped the `monorepo` packages to `1.57.2`
   and generated AI-enhanced release notes.

2. **CI runs on this PR** — the full test suite (unit tests, lint, type
checks, build)
   must pass before merging. This is the review gate.

3. **Review the release notes** in `release-notes.md` in this PR.
If a Notion draft was created, you can edit the release notes there
before merging.

4. **When this PR is merged**, the `release / publish` workflow
automatically:
   - Builds all packages
   - Publishes the `monorepo` packages to npm at version `1.57.2`
   - Creates git tag `monorepo/v1.57.2`
   - Creates a GitHub Release with the final release notes

### Before merging

- [ ] CI is green (tests, lint, types, build)
- [ ] Version bumps look correct
- [ ] Release notes are accurate (edit in Notion if a draft was created)

---

> **Do not merge until CI is fully green.** The full test suite runs
automatically on this PR.
2026-05-13 16:43:11 -07:00
Jordan Ritter a187e6b64c fix(react-core): fix flaky CopilotChatPerf e2e test
Harden rAF cleanup and timing assertions in the performance
test to prevent intermittent failures on Node 20.
2026-05-13 15:50:13 -07:00
Jordan Ritter 20184e1324 feat(react-native): export full v2 API surface with attachment support
15+ type re-exports from headless layer. expo-document-picker and
expo-file-system as optional peer deps. InterruptEvent,
ReactFrontendTool, ReactHumanInTheLoop added to headless.ts.
2026-05-13 15:38:55 -07:00
tylerslaton 1b14504788 chore: release monorepo v1.57.2 2026-05-13 00:40:27 +00:00
Tyler Slaton 442d2150c3 feat(react-core): add position prop to CopilotSidebar (left/right) (#4710)
## What does this PR do?

Adds a `position?: \"left\" | \"right\"` prop to the v2 `CopilotSidebar`
(and the underlying `CopilotSidebarView`), letting consumers anchor the
sidebar to either side of the viewport. Defaults to `\"right\"` so
existing usage is unchanged.

```tsx
<CopilotSidebar position=\"left\" />
```

### What changes when `position` flips

- **Anchor:** `cpk:right-0` ↔ `cpk:left-0`
- **Border side:** `cpk:border-l` ↔ `cpk:border-r`
- **Off-screen translate (closed state):** `cpk:translate-x-full` ↔
`cpk:-translate-x-full`
- **Body push margin:** `document.body.style.marginInlineEnd` ↔
`marginInlineStart` (with the matching `transition` CSS property name)
- **Aside element:** picks up a `data-position` attribute for
styling/test hooks

`position` is in the `useLayoutEffect` deps, so toggling it at runtime
cleans up the prior side's body margin before applying the new one.

### Tests

New `CopilotSidebarView.position.test.tsx` (7 cases) —
default/right/left class assertions, off-screen translate direction, and
verification that the wrapper forwards through to the view. All 32
sidebar-area tests pass; full react-core suite (1167 tests) green with
no regressions.

### Storybook

Added `RightPosition` and `LeftPosition` stories under
`UI/CopilotSidebarView` for visual diffing.

## Related PRs and Issues

- N/A

## Checklist

- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [ ] If the PR changes or adds functionality, I have updated the
relevant documentation
- [x] \"Allow edits by maintainers\" is checked

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-07 16:39:34 -07:00
github-actions[bot] 08a09ab950 style: auto-fix formatting 2026-05-07 23:01:54 +00:00
Tyler Slaton 3626bf1c53 fix(react-core): mirror sidebar toggle button when position="left"
The toggle button is hardcoded right-anchored (cpk:bottom-6 cpk:right-6).
When the sidebar sits on the left, the button should mirror to the left
so it lives behind/under the chat panel — otherwise it floats on the
opposite side from the sidebar it controls.

CopilotSidebarView now passes a position-aware className override into
the toggle slot (left-6 + right-auto, merged via tailwind-merge so the
default right-6 is dropped). Behavior on the right is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:00:24 -07:00
github-actions[bot] 1ed859707e style: auto-fix formatting 2026-05-07 20:52:15 +00:00
Tyler Slaton 68d0885d27 feat(react-core): add position prop to CopilotSidebar (left/right)
Lets consumers anchor the v2 CopilotSidebar to either side of the
viewport instead of the hardcoded right side. The prop flips the fixed
anchor, the border side, the off-screen translate direction, and the
body push margin (marginInlineStart vs marginInlineEnd) so the layout
mirrors correctly. Defaults to "right" for backward compatibility.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 13:49:22 -07:00
Alem Tuzlak 5d95e8e102 Merge branch 'main' into blitz/lgp-genuine-pass/integration 2026-05-07 21:17:15 +02:00
tylerslaton 5164ae303f chore: release monorepo v1.57.1 2026-05-07 16:41:22 +00:00
Alem Tuzlak ba60df5d33 feat(showcase/langgraph-python): add per-tool testids
Add stable testids and rendering surfaces for the three tool-rendering
cells so the e2e suite can distinguish each cell's strategy:

- tool-rendering: register useRenderTool for get_stock_price and
  roll_d20; new StockCard / D20Card components with testids
  stock-card / d20-card / stock-price / stock-change / d20-value.
  Rename FlightListCard testid flight-list-card -> flights-card.
- tool-rendering-default-catchall: drop the custom shadcn
  useDefaultRenderTool registration so the cell is truly zero
  custom-render-hooks. The framework's built-in
  DefaultToolCallRenderer now paints every tool call, with stable
  data-testid='copilot-tool-render' wrapper plus data-tool-name,
  data-args, and data-result attributes for inspection without
  expanding the card.
- tool-rendering-custom-catchall: rename the wildcard renderer's
  testids from custom-catchall-* to custom-wildcard-* so the cell
  is distinguishable from the (now-OOTB) default-catchall demo.
- packages/react-core: when no per-tool / wildcard renderer is
  registered, useRenderToolCall now falls back to the built-in
  DefaultToolCallRenderer instead of returning null.
2026-05-07 17:55:02 +02:00
Markus Ecker 79fb5af452 Merge remote-tracking branch 'origin/main' into mme/register-proxied-agent
# Conflicts:
#	packages/react-core/src/v2/hooks/__tests__/use-agent-thread-isolation.test.tsx
#	packages/react-core/src/v2/hooks/use-agent.tsx
#	packages/web-inspector/src/styles/generated.css
2026-05-07 14:20:55 +02:00
Jordan Ritter 164897647e feat: add @copilotkit/react-native package (#3633)
## Summary

- Extract `CopilotKitContext` and `useCopilotKit` into standalone
`context.ts` in react-core, enabling cross-platform reuse without web
dependencies
- Add new `@copilotkit/react-native` package with lightweight provider,
polyfills, and streaming fetch
- All hooks (`useAgent`, `useFrontendTool`, `useHumanInTheLoop`, etc.)
are re-exported directly from react-core — no reimplementation

## Motivation

CopilotKit's React hooks are platform-agnostic, but the barrel import in
`@copilotkit/react-core` pulls in web-only dependencies (Radix UI, Lit,
A2UI renderer, react-dom, CSS). This makes the package unusable in React
Native without extensive Metro shimming.

By extracting the React context into a standalone entry point
(`@copilotkit/react-core/v2/context`), the new
`@copilotkit/react-native` package can provide its own lightweight
provider while reusing all existing hooks.

## What's in `@copilotkit/react-native`

| Export | Description |
|--------|-------------|
| `CopilotKitProvider` | Lightweight provider — no DOM, CSS, Radix, Lit,
or A2UI deps |
| `installStreamingFetch()` | XHR-based streaming fetch for
`response.body.getReader()` support |
| `@copilotkit/react-native/polyfills` | All polyfills at once
(ReadableStream, TextEncoder, crypto, DOMException, window.location) |
| `@copilotkit/react-native/polyfills/*` | Granular per-polyfill imports
(`/streams`, `/encoding`, `/crypto`, `/dom`, `/location`) for users who
need to avoid overriding their own shims |
| `useAgent`, `useFrontendTool`, etc. | Re-exported from react-core
(shared context) |

## Usage

```tsx
// index.js (entry point, before other imports)
import "@copilotkit/react-native/polyfills";
import { installStreamingFetch } from "@copilotkit/react-native";
installStreamingFetch();

// App.tsx
import { CopilotKitProvider, useAgent, useCopilotKit } from "@copilotkit/react-native";

function App() {
  return (
    <CopilotKitProvider runtimeUrl="https://your-server/api/copilotkit">
      <ChatScreen />
    </CopilotKitProvider>
  );
}
```

## Test plan

- [x] `nx run react-core:build` passes
- [x] `nx run @copilotkit/react-native:build` passes
- [x] `nx run react-core:test` — all 1153 tests pass
- [x] Manual test in React Native app (tested during development with
bare RN 0.84 project)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-06 16:46:38 -07:00
Maxim 31061a1d23 test: add react-native tests and update react-core test imports
93 tests for react-native: streaming-fetch (36), provider (17),
polyfills (20), headless integration (9 provider + error boundary).
Update react-core test vi.mock paths from providers/CopilotKitProvider
to context module. Update useAgent throttle tests for batched
forceUpdate.
2026-05-06 16:42:15 -07:00
Maxim c3c30969e4 refactor: extract react-core context and headless hook exports
Extract CopilotKitContext, useCopilotKit, and LicenseContext into
src/v2/context.ts. Add src/v2/headless.ts barrel export for
platform-agnostic hooks. Add v2/context and v2/headless entry
points to tsdown config and package.json exports. Update all hook
imports to use the new context module. Always subscribe to onError
in web provider (matching RN pattern). Use batchedForceUpdate for
onMessagesChanged. Replace extraDeps spread with JSON.stringify in
useFrontendTool and useRenderTool dependency arrays.
2026-05-06 16:42:04 -07:00
Markus Ecker a83acc7fb8 fix(react-core): IntelligenceIndicator matches the renamed copilotkit_knowledge_base_shell tool
The Intelligence platform's MCP tool was renamed from `bash` to
`copilotkit_knowledge_base_shell` (intelligence/mme/integrate-sl
4256c13). Update the indicator's `DEFAULT_TOOL_PATTERNS` to match the
new name so the pill keeps rendering on the right assistant slots.

Test fixtures that previously used the bare `bash` name follow the
rename — both the default in `emitAssistantMessageWithToolCalls` and
the explicit `tc_match` entry in the tool-match condition test.
2026-05-06 17:33:45 +02:00
Markus Ecker 5b11748065 docs(react-core): refresh IntelligenceIndicator auto-mount comment
The previous comment referenced a "200 ms poll interval" that the
indicator no longer uses (polling was removed when we switched to the
tool-call pending-grace timer). Updates the rationale to mention the
current self-gates (latest matching-assistant slot + pending grace
window).
2026-05-06 12:18:14 +02:00
Markus Ecker ee1856f1ba refactor(react-core): minimize MemoizedCustomMessage delta to just the auto-mount
Reverts the cosmetic changes that crept in alongside the auto-mount
edit — restores `stateSnapshot?` (always passed at runtime, no functional
difference), the original concise comments around the memo's comparison
function, and the original combined value+type imports. The only
remaining framework change in this PR is the new auto-mount block:
when `copilotkit.intelligence !== undefined` and the message is an
assistant message, push an `<IntelligenceIndicator>` after the message
slot.

Indicator e2e suite still green (10/10).
2026-05-06 12:16:32 +02:00
Markus Ecker af9ea8b987 refactor(core,docs): rename ProxiedCopilotRuntimeAgent.remoteAgentId → runtimeAgentId
Renames the proxy-config field, the field on the agent instance, and
all matching references in tests and the useCopilotKit reference page.
"runtime" reads more naturally now that the proxy concept is documented
as "a local agent that delegates to a runtime agent" rather than
"remote agent" — the latter conflates with `remoteAgents` (the
registry of agents fetched from the runtime), which keeps its name.

No behavioral change; the field still controls the outbound REST URL
used by the proxy.
2026-05-06 12:01:37 +02:00
Markus Ecker b63602241d refactor(react-core): drop MemoizedCustomMessage's run-state inputs
Removes the numberOfMessagesInRun, isInLatestRun, and isRunning props on
MemoizedCustomMessage along with the per-render runMetadata derivation
that fed them. Authored renderers observe run state via useAgent's
OnRunStatusChanged / OnMessagesChanged subscriptions, which forceUpdate
the renderer independently of the memo's bail-out — the extra
invalidation inputs added nothing for that canonical path and only
masked staleness for renderers that read run state from closure
without subscribing.

The IntelligenceIndicator itself uses useAgent and remains correct.

Net change: ~95 lines removed; one less O(n) scan through messages per
chat re-render. All chat e2e tests (587) pass, including the indicator
suite (10).
2026-05-06 11:57:44 +02:00
Markus Ecker 8623c4a9b5 fix(react-core): IntelligenceIndicator drops polling, gates on tool-call pending window
Replaces the agent.isRunning-driven phase entry (and its 200 ms polling
fallback) with a 100 ms grace timer on unresolved matching tool calls.
Replay flashes (tool call + result in the same tick during connectAgent
history hydration) no longer cross the threshold, so the pill stops
appearing on completed historical runs.

Spinner exits as soon as either agent.isRunning falls or a "real
follow-up" message arrives — assistant prose, a fresh user turn, or
anything that isn't a tool result / empty-content tool-call wrapper.
Multi-step tool chains stay on a single continuous pill (the
latest-matching-assistant slot still moves between messages without a
fade animation when the next bash assistant lands).

Polling and the snapshot-subscriber comment were a misdiagnosis of a
test artifact: useAgent's OnRunStatusChanged subscription is what the
rest of CopilotKit (CopilotChat stop button, MCPAppsActivityRenderer,
chat suggestions) relies on for isRunning falling-edge re-renders.

Tests cover three new cases: replay-flash suppression, multi-step
continuity across tool-result interleaving, and exit-on-prose-followup.
2026-05-05 17:57:41 +02:00
Lukas Moschitz 7baf4d05e8 fix(react-core): IntelligenceIndicator pill shrinks to content width
The auto-mount in `CopilotChatMessageView` puts the indicator inside
a flex column container (`cpk:flex cpk:flex-col`) whose default
`align-items: stretch` was overriding the pill's intended
`display: inline-flex` shrink-to-content behaviour, leaving the
pill stretched to the full chat width — out of proportion with the
short label.

Add `align-self: flex-start` to opt the pill out of the parent's
stretch. Pill renders at content width, anchored to the chat's
left edge in line with the assistant message bubble it represents.
2026-05-05 17:28:01 +02:00
Lukas Moschitz ddb9e244f6 fix(react-core): IntelligenceIndicator no longer depends on getRunIdForMessage
Two SDK gaps surface in real MCP recall flows that the previous gate
revision still tripped on:

- The bash-issuing assistant message is consistently missing from
  `stateManager.messageToRun` even though it is the message the
  indicator needs to attach to. The first gate
  `if (!messageRunId) return null;` fired before any of the slot
  logic ran, so the pill never rendered.
- The threadId key in `messageToRun` can drift out of sync with the
  chat configuration's threadId — same lookup, same null, same gate.

Drop the run-id dependency entirely. The indicator only needs
`agent.messages` and `message.role` / `message.toolCalls`, both of
which the runtime populates correctly in every observed flow. The
walk just finds the latest assistant-with-matching-tool-call across
`agent.messages`; tool result messages (`role: "tool"`) and prose-
only assistants are skipped without invalidating the slot.

Cross-run isolation moves to the phase machine: once an indicator
reaches `phase === "hidden"` it stays there. A later run on the
same chat does not resurrect a faded pill; the new run mounts fresh
indicator instances on its own assistant messages.

Net behaviour:
- Through a multi-step tool chain the pill stays put on the bash-
  issuing assistant.
- When the run finishes, the existing 500 ms debounce -> 800 ms
  check-hold -> 480 ms fade lifecycle plays out unchanged, then
  hidden becomes terminal.
- Subsequent runs are independent: their first assistant-with-tool-
  call message becomes the new canonical slot.
2026-05-05 17:28:01 +02:00
Lukas Moschitz 960ab91c13 fix(react-core): IntelligenceIndicator stays through tool-result interleaving
The pill's gate "the message must be the last message of its run" was
suppressed every time a `role: "tool"` result arrived between
successive assistant-with-tool-call messages. Real MCP recall flows
always interleave tool results between assistant tool-call messages,
so the assistant message holding the matching tool call lost its
"last in run" claim immediately, the indicator returned `null`, and
the pill flashed off. By the time the run finished, the final
prose-only assistant message was the last in the run and the pill
on the bash-bearing assistant stayed suppressed. Net result: the
user saw no pill at all during a real recall.

Change the gate to "the latest assistant-with-matching-tool-call
message in the run". Tool result messages (`role: "tool"`) and
prose-only assistant messages now skip through the walk without
invalidating an earlier matching-assistant's claim on the slot, so
the pill stays continuously through a multi-step tool chain and
transitions to checkmark on `isRunning` falling (debounced 500 ms,
unchanged) as before.

The existing test suite did not cover this case — none of the
walkthrough scenarios emit `role: "tool"` between successive
assistant messages. A regression test that interleaves a tool result
will land alongside this fix.
2026-05-05 17:28:01 +02:00
tylerslaton 490440a0e4 chore: release monorepo v1.57.0 2026-05-04 17:33:59 +00:00
Markus Ecker e8192a1d52 fix(react-core): address CR-loop findings on IntelligenceIndicator
Round-1 review on the indicator branch surfaced perf and defensive
hardening items. Tests: react-core 1158 — all green.

- CopilotChatMessageView auto-mount now gates on
  `message.role === "assistant"` in addition to
  `copilotkit.intelligence !== undefined`. Eliminates wasted
  `useAgent` subscriptions, 200 ms polling intervals, and four
  `useEffect`s on every user / activity / reasoning slot — the
  indicator's own role gate would short-circuit anyway, but only
  after a subscribe + interval-set + cleanup cycle on every render.

- IntelligenceIndicator's `toolCalls` access is now defensive:
  `Array.isArray(...)` guard and `tc?.function?.name` chain. A
  malformed agent payload no longer crashes the chat tree at
  `.some(...)`.

Comment fixes:

- CopilotChatMessageView: stale `CopilotKitProvider.intelligenceIndicator.e2e.test.tsx`
  reference updated to the actual path
  `intelligence-indicator/__tests__/IntelligenceIndicator.e2e.test.tsx`.

- IntelligenceIndicator `ISRUNNING_POLL_MS` JSDoc rewritten — the
  prior version claimed `addMessage` iterates subscribers live during
  streaming. In fact AG-UI's `runAgent` snapshots subscribers and
  threads them through the entire pipeline (including
  `processApplyEvents` for streaming events), so a late-mounted
  subscriber misses both `onMessagesChanged` AND `onRunFinalized`
  from the run's pipeline. The poll fallback is the only thing that
  catches the falling edge.

- `globals.css` pill-styles port comment listed `#BEC2FF` as part of
  the palette but that hex doesn't appear anywhere in the rules.
  Updated to the actual swatches: text #5B21B6, icon #7C3AED, border
  #9599E0, gradient #EEE6FE, shadow #5E64AD.
2026-05-04 17:39:06 +02:00
Markus Ecker 678d143b27 feat(react-core): IntelligenceIndicator auto-mounts when intelligence is configured
Adds an official "Using CopilotKit Intelligence" pill, ported from the
visuals of CopilotKit/Intelligence#155. Mounts automatically — the
caller never adds the renderer themselves.

Behavior:

- `CopilotChatMessageView` mounts an `<IntelligenceIndicator>` for
  every message slot whenever `copilotkit.intelligence !== undefined`.
  When intelligence is not configured, no indicator instance is
  mounted at all (no perf cost).

- `IntelligenceIndicator` self-gates so only the canonical message
  renders a pill — last message of the latest in-flight run, with at
  least one tool call whose name matches a pattern from
  `DEFAULT_TOOL_PATTERNS` (currently `[/^bash$/]`, the Intelligence
  MCP server's canonical tool).

- The "exactly one pill at any moment" guarantee is structural: only
  one message ever satisfies (last in run) + (run is latest) +
  (matching tool call), so each renderer invocation decides
  independently and the result is one pill in the DOM.

Phase machine (per-instance, all timers local):
  - `spinner` while `agent.isRunning`
  - → `check` after `agent.isRunning` falls (debounced 500 ms to
    absorb step-boundary `RUN_FINISHED → RUN_STARTED` blips inside
    one user turn)
  - → `fading` after `CHECK_HOLD_MS` (800 ms)
  - → `hidden` after `FADE_OUT_ANIMATION_MS` (480 ms)

A 200 ms `agent.isRunning` poll closes the AG-UI snapshot-subscriber
gap (subscribers added INSIDE a run never see that run's
`onRunFinalized`).

Public surface (via `@copilotkit/react-core/v2`):

- `IntelligenceIndicator` — the pill component, exposed for tests
  and inspection. Most callers don't import it directly; the
  auto-mount in `CopilotChatMessageView` does the work.

There is no factory and no provider — auto-registration eliminates
the prior `createIntelligenceIndicatorRenderer` factory and any
`IntelligenceIndicatorProvider`/coordination store.

Tests (all live next to the component):

- 1 walkthrough (Run A → Run B with multiple messages, asserts the
  pill follows the canonical "last message of latest in-flight run"
  slot through every phase, with no `renderCustomMessages` prop on
  the test setup)
- 4 condition tests (last-in-run / in-flight / latest-run /
  tool-match), each pinning one gate
- 1 intelligence-gate test (no pill when `copilotkit.intelligence`
  is undefined)
- 1 explicit auto-registration assertion (no `renderCustomMessages`
  prop is required for the pill to render)

7 tests, react-core 1157 → 1158.
2026-05-04 17:26:11 +02:00
Markus Ecker 7829191350 test(react-core): intelligence-indicator renderer + MemoizedCustomMessage gating signals
Adds three new memo gating signals to MemoizedCustomMessage so custom
message renderers stay reactive across the structural events that affect
"is this slot still authoritative?" decisions:

- numberOfMessagesInRun — invalidates when peers stream into the same run,
  so renderers gating on "last message of the run" stay correct.
- isInLatestRun — invalidates when a newer run starts, so renderers gating
  on "is this the latest activity?" can drop their badges on completed runs.
- isRunning (gated on isInLatestRun) — invalidates exactly twice per run on
  the latest run's slots (start, end), preserving the perf-test guarantee
  that completed runs' messages skip re-renders during streaming.

CopilotChatMessageView computes these per slot via getRunIdForMessage and
passes them down. Helper getNumberOfMessagesInRun lives next to the call
site for clarity.

New e2e test at CopilotKitProvider.intelligenceIndicator.e2e.test.tsx
exercises an "Using CopilotKit Intelligence" renderer that gates on:
position === "after", last-in-run, agent.isRunning, and run-is-latest.
The walkthrough scenario drives Run A then Run B with multiple messages
each, verifying the indicator only appears on the canonical slot at each
phase. Four condition-focused tests pin each gate individually.

Includes IsRunningAccurateMockAgent — a local subclass that makes run()
return a per-run observable terminating on RUN_FINISHED/RUN_ERROR. The
shared MockStepwiseAgent.run() returns the un-terminating subject for
backward compatibility, so emit(RUN_FINISHED) on it doesn't trigger
AbstractAgent's finalize → onRunFinalized → useAgent re-render path. The
subclass scopes the fix to this file without disturbing other tests.
2026-05-04 17:26:11 +02:00
Markus Ecker 9abce2c9bc fix(core,react-core): address CR-loop findings on registerProxiedAgent + cloning revert
Round-1 review found seven actionable items; this commit lands fixes for
all of them. Tests: core 425, react-core 1151, web-inspector 7 — all green.

Real bugs fixed:

- run-handler.ts: dropped the stale `agent` argument on the
  `reloadSuggestions(agentId, agent)` call. The signature was tightened
  to `(agentId)` when the consumerAgent parameter was removed; the call
  site wasn't updated, leaving a TS-2554 build break.

- agent.ts: tightened `routedAgentId(): string` to throw when both
  `agentId` and `remoteAgentId` are unset, instead of returning
  `string | undefined`. Removes two `!` non-null asserts in
  `#runViaHttp` / `#connectViaHttp` and the silent
  `/agent/undefined/connect` URL path.

- agent.ts: marked `remoteAgentId` `readonly`. The field was publicly
  mutable but `super.url` is baked at construction — mutating
  `remoteAgentId` post-construction silently desyncs the REST run URL
  from the routing decision elsewhere. `readonly` prevents.

- agent-registry.ts: the registerProxiedAgent collision check now uses
  `Object.prototype.hasOwnProperty.call(this._agents, agentId)` instead
  of `agentId in this._agents`. The `in` operator walks the prototype
  chain, so an agentId of `"__proto__"`, `"constructor"`, etc. would
  falsely test as already-registered.

- core.ts: the onAgentsChanged handler now mirrors the thread-store
  unregister loop with a parallel
  `stateManager.unsubscribeFromAgent(agentId)` for any agentId in
  previousAgentIds but absent from the current snapshot. Without this,
  `unregister()`'s state-manager subscription leaked.

Comment / test cleanup:

- CopilotChatView.tsx:92: stale "empty cloned agent" reference in the
  `isConnecting` JSDoc rewritten to "empty agent instance" — clones are
  gone.

- core-register-proxied-agent.test.ts: split the misleading "registering
  before runtime connects yields a proxy in pending runtimeMode" test
  (which exercised the no-runtimeUrl path, never the pending path) into
  two: one for the no-runtimeUrl case, one that actually constructs a
  core with a runtimeUrl and asserts `runtimeMode === "pending"`.
2026-05-04 17:20:37 +02:00