Commit Graph

1227 Commits

Author SHA1 Message Date
Markus Ecker abd0d5c11c fix: add path binding schema rule to A2UI generation prompts
LLMs sometimes use path bindings (e.g. {"path": "/chartData"}) on
component properties that only accept literal values, causing silent
render failures. The new guideline tells the LLM to check the schema's
anyOf type before using path bindings.
2026-04-15 11:51:05 +02:00
Jordan Ritter aff9350f17 fix: pass toolCallId to useRenderTool render components (#3741) 2026-04-14 16:24:45 -07:00
Jordan Ritter d534ccc7a0 fix: call onChange("") after send in controlled input mode (#3593) 2026-04-14 16:24:28 -07:00
Jordan Ritter 78c65a8a38 fix: ensure tool_result and tool_use messages stay paired after token trimming (#2450) 2026-04-14 16:23:34 -07:00
Jordan Ritter 97acd2e4d9 fix: add Zod v4 compatibility for schema-to-JSON conversion
Detect Zod v4 schemas by checking for a toJSONSchema() method on the
schema object. When present, call it directly instead of routing through
zod-to-json-schema (which cannot handle Zod v4 internals).

Priority order:
1. Standard JSON Schema V1 (~standard.jsonSchema.input)
2. Zod v4 native (schema.toJSONSchema())
3. Zod v3 fallback (injected zodToJsonSchema)

Removes the dead vendor === "zod4" check (Zod v4 reports "zod") and
the _def duck-typing fallback (unnecessary with toJSONSchema detection).

Closes #3636
2026-04-14 16:15:58 -07:00
Jordan Ritter a7cf38211c fix: add configurable maxInputTokens to OpenAI and Anthropic adapters (#2405) 2026-04-14 16:11:39 -07:00
Jordan Ritter a46218557c fix: add remarkPlugins/rehypePlugins passthrough support (#2296) 2026-04-14 15:55:08 -07:00
Jordan Ritter bcea46771b fix: handle urlTransform=null correctly in Markdown component
The truthiness check swallowed null, which is a valid value in
react-markdown that explicitly disables the default URL sanitizer.
Changed to an explicit undefined check.
2026-04-14 15:53:40 -07:00
Jordan Ritter 0c4383d74c fix: add satisfies constraint and improve test coverage for onAfterRequest
- Add `satisfies OnAfterRequestOptions` for compile-time type safety (consistent with onBeforeRequest)
- Replace `(m: any)` casts with type predicates and explicit `as unknown as Message[]`
- Add TODO comment for hardcoded empty properties
- Expand test to verify all 6 fields of OnAfterRequestOptions
- Add edge case tests for undefined messages and missing threadId/runId
2026-04-14 15:48:12 -07:00
Jordan Ritter 8aa369b58f fix: preserve nullable semantics and add Zod support for null-union types
- Mark parameters as optional when null is present in the type union
- Add matching null-union handling to convertJsonSchemaToZodSchema
- Add 7 tests covering null-union edge cases for both converters
2026-04-14 15:47:40 -07:00
Jordan Ritter f403105ad9 fix: only set hasReceivedContent for processed content blocks
Move hasReceivedContent flag inside each content block type handler
so that skipped unknown tool_use blocks do not prevent the fallback
response mechanism from activating. Add tests for unknown tool
skipping behavior.
2026-04-14 15:47:27 -07:00
Maxim 5058d195cc refactor: test hygiene for web-inspector spec
Extract shared helpers to reduce duplication and centralize unavoidable
casts. Add simulateSetState to mock controller to eliminate double-casts
in the new onStateChanged test. Promote mockClipboard to describe scope
to remove navigator clipboard cast in assertion. Add try/catch error
handling to syncAgentMessages and syncAgentState.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 00:43:49 +02:00
Jordan Ritter 4bd57af65d test: add tests for array content normalization in TOOL_CALL_RESULT
Cover the MCP adapter scenario where content arrives as an array of
{type:"text", text:string} objects, and verify non-text parts are
filtered out during normalization.
2026-04-14 15:41:25 -07:00
Jordan Ritter afc36a3da9 fix: mock navigator in clipboard test for Node 20 compatibility 2026-04-14 15:11:35 -07:00
Maxim df199123da fix: inspector syncs state on direct agent.setState()
When using selfManagedAgents, calling agent.setState() directly only
fires onStateChanged — the inspector subscribed to onStateSnapshotEvent
(pipeline-only) but not onStateChanged, leaving the "Current State"
panel permanently stale. Add onStateChanged handler mirroring the
existing onMessagesChanged pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 00:08:53 +02:00
Jordan Ritter 39b4ea6ecc docs: clarify client-side debug prop behavior
Updated JSDoc and troubleshooting docs to accurately describe that
the client-side debug prop forwards config to the AG-UI transport
layer, not CopilotKit's own logging. Removed fabricated console.debug
output examples that don't exist.
2026-04-14 14:58:44 -07:00
Jordan Ritter 295a1e609e fix: sync debug prop changes at runtime in CopilotKitProvider
debug was only read at construction time. Added setDebug() to
CopilotKitCore and added it to the provider's prop-sync useEffect
so runtime changes to the debug prop take effect.
2026-04-14 14:58:33 -07:00
Jordan Ritter fde4e0b424 fix: cache pino debug logger on runtime instead of creating per-request
createLogger() was called on every request when debug was enabled,
instantiating a new pino + pino-pretty stream each time. Now creates
a single logger in the runtime constructor and passes it to handlers.
Added test verifying pre-created logger is reused.
2026-04-14 14:58:22 -07:00
Jordan Ritter 6689de4522 fix: thread debug config through to ProxiedCopilotRuntimeAgent
Debug config was silently dropped because ProxiedCopilotRuntimeAgentConfig
had no debug field. Now stores it in the constructor, resolves it in
AgentRegistry before passing, and clone() preserves it. Added 6 tests
verifying the full threading chain.
2026-04-14 14:58:09 -07:00
Jordan Ritter 971a8165aa fix: default verbose to false when debug: true to prevent PII exposure
When users pass the boolean shorthand `debug: true`, verbose previously
defaulted to true, logging full event payloads including user messages,
tool args, and state snapshots. Now defaults to false — users must
explicitly opt in with `debug: { verbose: true }`.
2026-04-14 14:57:22 -07:00
Jordan Ritter 2438896409 fix: respect user expand/collapse intent in reasoning message (#3897)
## Summary

- **Component bug fix:** `CopilotChatReasoningMessage` auto-collapse
`useEffect` unconditionally called `setIsOpen(false)` when streaming
ended, overriding any manual expand/collapse the user had performed.
Added a `userToggledRef` that tracks explicit clicks so the effect only
auto-collapses when the user hasn't interacted.
- **Flaky test fix:** `CopilotChat.e2e.test.tsx` reasoning toggle test
used `fireEvent.click` without `act()`, causing React 18 to defer the
state update through its scheduler. This raced with `waitFor` polling on
slow CI runners (Node 20.x/22.x), producing nondeterministic failures
across multiple PRs.

## Test plan

- [x] Existing reasoning message tests pass with both fixes applied
- [x] Pre-commit hooks (lint, format, test, build) pass
- [ ] Verify intermittent CI failures on unit (20.x/22.x) no longer
reproduce

Note: This fixes the intermittent unit test failures that have been
appearing across multiple unrelated PRs.
2026-04-14 14:35:38 -07:00
Jordan Ritter 1e0de53a25 fix: add null check for navigator.clipboard across all copy-to-clipboard calls (#2114) (#3813)
Fixes #2114

Red-green tested locally.
2026-04-14 14:31:13 -07:00
Jordan Ritter 5aa158da03 fix: surface TOAST/BANNER errors when showDevConsole=false (#3789)
## Summary
- Fixes #2431
- The `routeError` function in `copilot-messages.tsx` returned early
when `showDevConsole=false`, suppressing ALL errors including
user-visible ones (TOAST and BANNER visibility)
- Now only `DEV_ONLY` and `SILENT` errors are suppressed in production;
`TOAST` and `BANNER` errors are always surfaced to the chat UI
- Also fixes the non-GraphQL error handler which had the same
early-return bug

## Test plan
- [x] Added `error-visibility-prod.test.tsx` covering TOAST, DEV_ONLY,
and SILENT visibility behavior
- [x] All 1073 existing react-core tests pass
- [x] Build passes
2026-04-14 14:26:17 -07:00
Jordan Ritter 0106b1bf19 fix: remove unstable key on CodeBlock to prevent flickering during streaming (#3826)
## Summary

- Removes the `key` prop from `CodeBlock` in `Markdown.tsx` entirely
- The original `Math.random()` key caused React to remount the component
on every render, producing visible flickering
- A content-based key (language + content prefix) still changes every
streaming token, causing the same problem
- Without an explicit key, React uses positional identity — stable
across re-renders while content streams in

Closes #2669

## Test plan

- [x] `@copilotkit/react-ui` tests pass
- [x] `@copilotkit/react-ui` build succeeds
- [ ] Manual: verify code blocks no longer flicker during streaming in
chat UI
2026-04-14 14:26:13 -07:00
Jordan Ritter 2c45e24e90 fix: handle anyOf/oneOf/$ref/null in JSON schema to Zod conversion (#3849)
## Summary
- Handle `anyOf`, `oneOf`, `$ref`, and null type entries when converting
JSON schema to Zod schemas
- Prevents runtime errors when LLM tool parameters use union types or
nullable fields

Closes #2220

---
*Split from #3847*
2026-04-14 14:26:09 -07:00
Jordan Ritter 1e5c0ba9ec fix: support OpenAI SDK v5 by falling back from openai.beta to openai.chat.completions (#1979) (#3810)
Fixes #1979

## Summary

- Add `isOpenAIV5()` detection helper that checks whether `beta.chat`
was removed (v5 promoted it to `chat.completions`)
- Add `getChatCompletionsForStreaming()` helper that routes to the
correct completions namespace per SDK version
- Migrate `OpenAIAdapter` to use the new helper instead of direct
`beta.chat.completions` access
- Migrate `OpenAIAssistantAdapter` `runs.retrieve()` and
`submitToolOutputsStream()` to use v5 named path params (e.g.
`retrieve(runId, { thread_id })` instead of positional
`retrieve(threadId, runId)`)
- Add `openai` to peerDependencies with `^4.85.1 || ^5.0.0` range
- Add 11 unit tests covering v4/v5 detection, streaming dispatch, and
named path param calling conventions

## Notes

The remaining `openai.beta.threads.*` calls (`threads.create`,
`messages.create`, `runs.stream`) do NOT need migration because:
1. `beta.threads` still exists in v5 (only `beta.chat` was removed)
2. These methods have single path params, so their signatures are
unchanged

## Test plan

- [x] All 11 v5 compat tests pass (`nx run @copilotkit/runtime:test`)
- [x] Runtime package builds successfully (`nx run
@copilotkit/runtime:build`)
- [x] Pre-commit hooks pass (lint, format, publint, attw)
2026-04-14 14:26:05 -07:00
Jordan Ritter 9e5b458612 fix: use div instead of p tag in Markdown to prevent hydration errors (#2234) (#3821)
## Summary

Fixes #2234

React's hydration fails when block-level elements (like `<div>`) are
nested inside `<p>` tags in the Markdown component. Replaces the `<p>`
wrapper with `<div>` (adding `copilotKitParagraph` class for styling) to
prevent SSR hydration mismatches.

## Test plan

- [ ] Verify Markdown rendering in SSR context has no hydration errors
- [ ] Verify paragraph styling is preserved via `copilotKitParagraph`
class
2026-04-14 14:26:02 -07:00
Jordan Ritter 14eef93d20 fix: scope .dark CSS selectors to CopilotKit elements (#3850)
## Summary

- **console.css + input.css:** Scope `.dark` CSS selectors to CopilotKit
container elements (`.copilotKitDevConsole
.copilotKitDebugMenuTriggerButton` and `.poweredBy` respectively). The
original selectors had bare `.dark,` as standalone entries in
comma-separated selector lists, which applied styles to *any* element
with class `.dark` instead of scoping to CopilotKit elements.
- **colors.css:** Remove broken `:root` pseudo-element from
`body[style*="color-scheme: dark"] :root` — `:root` is `<html>`, which
cannot be a descendant of `<body>`, so this selector never matched
anything.
- **E2E tests:** 4 Playwright regression tests verifying dark mode
styles don't leak into host application elements.

Prevents CopilotKit dark-mode styles from leaking into the host
application.

Closes #2920

---
*Split from #3847*
2026-04-14 14:25:57 -07:00
Jordan Ritter e1ef523a3e fix: resolve agent factory functions in V1 CopilotRuntime constructor (#3865)
## Summary

- The V1 `CopilotRuntime` constructor did `{...endpointAgents,
...agents}` which silently spread a factory function to `{}`, destroying
all agents with no error or warning
- Anyone using the V1 API with a factory function (introduced in #3854)
got zero agents — complete silent data loss
- This wraps factory functions so endpoint agents are merged at
resolution time instead of construction time, matching how V2 already
handles it via `resolveAgents()`

Fixes the V1 path regression from #3854 (per-request agent factory,
issue #2941).

## Test plan

- [x] New test: factory function is preserved through constructor (not
spread to `{}`)
- [x] New test: factory resolves different agents per-request based on
headers
- [x] New test: endpoint agents are correctly merged with
factory-resolved agents
- [x] New test: static agent records still work (backward compat)
- [x] New test: promised agent records still work (backward compat)
- [x] Red-green verified: 4/5 tests fail without the fix, all 5 pass
with it
- [x] Full runtime test suite passes (1234 tests)
- [x] Full build passes
2026-04-14 14:06:14 -07:00
Jordan Ritter b9748a6e0e fix: widen openai peer dep range to include v6.x
The compatibility layer correctly handles v6 (same API surface as v5),
but the version range ^5.0.0 excluded v6.x. Changed to >=5.0.0 so
users on the latest openai SDK don't get peer dependency warnings.
2026-04-14 13:57:49 -07:00
Jordan Ritter a8b224e935 fix: replace unsafe type casts with proper type guards for OpenAI v4/v5 compat
- Remove all `as any`, `as Function`, and `as Record<string, unknown>` casts
  from production code in the OpenAI compatibility layer
- Introduce typed `OpenAIV4Beta` interface and `hasV4BetaChat` type guard
  for safe runtime detection of v4 vs v5 clients
- Extract `retrieveThreadRun` and `submitToolOutputsStream` helper functions
  into utils.ts with properly typed generic signatures, moving the v4/v5
  dispatch logic out of the assistant adapter
- Give `getChatCompletionsForStreaming` an explicit return type so callers
  no longer need secondary casts
- Update tests to exercise the new helpers directly instead of
  duplicating dispatch logic inline
2026-04-14 13:50:23 -07:00
Jordan Ritter fbf1af2419 fix: propagate copyToClipboard success result to CopyButton UI state
The CopyButton in react-core was showing the "copied" checkmark based on
an independent clipboard availability check rather than the actual copy
result. This meant a failed copy (e.g. permission denied) would still
show the success indicator. Now the onClick handler returns the boolean
from copyToClipboard, and handleClick uses that to drive the UI state.
Also removes unsafe type casts of onClick to Promise<void>.
2026-04-14 13:47:44 -07:00
Jordan Ritter 093f41907a fix: extract shared copyToClipboard utility to eliminate clipboard duplication
Address review feedback: extract the repeated clipboard availability check +
writeText + error handling pattern into a shared copyToClipboard() utility in
@copilotkit/shared. All 9 call sites across angular, react-core, and react-ui
now use the shared utility instead of duplicating the same code block.
2026-04-14 13:39:42 -07:00
Jordan Ritter b7b885e086 fix: scope dark theme CSS variables in colors.css
Same bug pattern as console.css and input.css: bare `.dark,` was a
standalone selector leaking all --copilot-kit-* CSS custom properties
onto any element with a .dark class. Also removed broken `:root`
pseudo-element from `body[style*="color-scheme: dark"] :root` — :root
cannot be a descendant of body, so this selector never matched.

Fix: drop standalone `.dark,` (redundant with `html.dark` and
`body.dark`) and remove the non-functional `:root` descendant.
2026-04-14 13:33:59 -07:00
Jordan Ritter 3d0873cc1e test: add userToggledRef behavior tests for reasoning message
Two new test cases covering the core behavioral fix:
- User collapses during streaming → panel stays collapsed after stream ends
- User collapses then re-expands during streaming → panel stays open after stream ends
2026-04-14 13:12:28 -07:00
Jordan Ritter 93547c933e test: wrap fireEvent.click in act() for deterministic reasoning toggle test
Without act(), React 18 defers the state update through its scheduler,
which can race with waitFor polling on slow CI runners (Node 20.x/22.x).
Wrapping in act() forces synchronous flush.
2026-04-14 12:42:06 -07:00
Jordan Ritter 8cf8f03a57 fix: respect user expand/collapse intent in reasoning message
The auto-collapse useEffect unconditionally called setIsOpen(false) when
streaming ended, overriding any manual expand/collapse the user had
performed.  Add a userToggledRef that tracks explicit clicks so the
effect only auto-collapses when the user hasn't interacted.
2026-04-14 12:41:22 -07:00
Jordan Ritter b63708490d fix: apply oxfmt formatting 2026-04-14 11:53:31 -07:00
github-actions[bot] 8933ee82b5 style: auto-fix formatting 2026-04-14 16:39:04 +00:00
Alem Tuzlak e977a49972 fix: address CR findings for debug mode feature
- Fix clone() dropping debug config on ProxiedCopilotRuntimeAgent
- Pass raw DebugConfig to agents instead of collapsing to boolean
- Clamp verbose to false when enabled is false
- Fix pino-pretty log format in docs (parentheses, timestamps, levels)
- Add loggedEventCount to doc example
- Fix "Agent run started/finished" → actual log messages in arch docs
2026-04-14 18:35:32 +02:00
Alem Tuzlak 488c7d00e0 fix: address PR review feedback for debug mode
- Count all emitted events unconditionally (eventCount), track separately
  how many were logged (loggedEventCount) — completion log shows both
- Remove dead `?? undefined` on runtime.debug (non-optional type)
- Update test to verify eventCount reflects actual events; add test with
  events: true to verify loggedEventCount
2026-04-14 18:34:49 +02:00
Alem Tuzlak 7e0a632e64 test: add debug mode tests for shared, runtime, and core packages 2026-04-14 18:34:47 +02:00
Alem Tuzlak 99c3a39a29 style: fix prettier formatting 2026-04-14 18:34:47 +02:00
Alem Tuzlak 4ec0230cf8 fix(runtime): guard debug property access for backward compat with mock runtimes 2026-04-14 18:34:46 +02:00
Alem Tuzlak 7b9abc142c feat(react-core): add debug prop to CopilotKit provider, thread to AG-UI agent 2026-04-14 18:34:45 +02:00
Alem Tuzlak 0b2731e8da feat(runtime): add debug logging to SSE event pipeline 2026-04-14 18:34:08 +02:00
Alem Tuzlak b9127c18c1 feat(runtime): accept debug config on CopilotRuntime constructor 2026-04-14 18:34:07 +02:00
Alem Tuzlak cc5410dc4f feat(shared): add DebugConfig type and resolveDebugConfig utility 2026-04-14 18:34:07 +02:00
Alem Tuzlak 983274f7c3 Merge branch 'main' into worktree-nested-tinkering-quail 2026-04-14 14:11:42 +02:00
Alem Tuzlak 19b99dd2ae fix(runtime): widen TanStack message content type for adapter compat (#3747)
## Summary

- Widen `TanStackChatMessage.content` from `TanStackContentPart[]`
  to `any[]` so messages from `convertInputToTanStackAI` are directly
  passable to any TanStack AI adapter without `as any` casts
- Split `TanStackContentPart` into a proper discriminated union with
  separate variants per modality
- Add `env.d.ts` with `vite/client` reference for CSS import types
- Fix `onError` callback shape in the example

## Test plan

- [x] All 17 multimodal TanStack tests pass
- [x] All 294 agent tests pass
- [ ] Verify no TS errors in react-router example IDE

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-14 14:11:18 +02:00