React StrictMode double-mounts components in development, causing
CopilotChat's connectAgent() useEffect to abort its in-flight fetch
on the first cleanup. This produced noisy "Agent execution failed:
AbortError: signal is aborted without reason" errors in browser
devtools.
Two fixes:
1. withAbortErrorHandling() in agent.ts now catches AbortError
(alongside the existing ZodError handling) and returns EMPTY,
preventing the error from reaching onError() which would log
"Agent execution failed:" to the console.
2. CopilotChat.tsx attaches .catch() to the fire-and-forget
detachActiveRun() call in the cleanup function. The promise
does not actually reject, but without an attached handler V8
flags the promise chain as unhandled when the abort signal
propagates through connected promises internally.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
<!--
Thank you for sending the PR! We appreciate you spending the time to
work on these changes.
Help us understand your motivation by explaining why you decided to make
this change.
**Please PLEASE reach out to us first before starting any significant
work on new or existing features.**
By the time you've gotten here, you're looking at creating a pull
request so hopefully we're not too late.
We love community contributions! That said, we want to make sure we're
all on the same page before you start.
Investing a lot of time and effort just to find out it doesn't align
with the upstream project feels awful, and we don't want that to happen.
It also helps to make sure the work you're planning isn't already in
progress.
As described in our contributing guide, please file an issue first:
https://github.com/ag-ui-protocol/ag-ui/issues
Or, reach out to us on Discord: https://discord.com/invite/6dffbvGU3D
You can learn more about contributing to copilotkit here:
https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md
Happy contributing!
-->
## What does this PR do?
(Describe the changes introduced in this PR)
## Related PRs and Issues
- (Direct link to related PR or issue, if relevant)
## Checklist
- [ ] 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
## Problem
When a HITL (Human-in-the-Loop) tool has no parameters, some providers
(e.g., Google ADK) send `arguments` as an empty string `""`.
`JSON.parse("")` throws `"Unexpected end of JSON input"`, crashing the
tool execution pipeline with an opaque error instead of executing the
tool with empty args.
Fixes#3263
## Root Cause
In `run-handler.ts`, both the specific-tool and wildcard-tool execution
paths call `JSON.parse(toolCall.function.arguments)` without checking
for empty/falsy values:
```ts
// Line 309 — specific tool path
parsedArgs = JSON.parse(toolCall.function.arguments); // crashes on ""
// Line 448 — wildcard tool path
parsedArgs = JSON.parse(toolCall.function.arguments); // crashes on ""
```
## Fix
Treat empty/falsy argument strings as `{}` (empty object) before
parsing:
```ts
const rawArgs = toolCall.function.arguments;
parsedArgs = rawArgs ? JSON.parse(rawArgs) : {};
```
This matches the existing defensive patterns:
- **v1 `agui-to-gql.ts`**: already catches parse errors and falls back
to `{}`
- **v2 `web-inspector`**: already checks `args === "" ` before parsing
(line 818)
## Changes
| File | Change |
|------|--------|
| `packages/v2/core/src/core/run-handler.ts` | Safe empty-args fallback
at both parse sites |
| `packages/v2/core/src/__tests__/core-edge-cases.test.ts` | Updated
test: empty args → handler called with `{}` |
| `packages/v2/core/src/__tests__/core-full.test.ts` | Updated test:
empty args → handler called with `{}` |
## Testing
- All 230 passing tests still pass (61 pre-existing failures in
unrelated packages unchanged)
- Updated 2 tests that previously expected a crash on empty args to
verify the handler is called with `{}`
Address review feedback:
- Extract parseToolArguments() to deduplicate empty/null/undefined handling
- Add debug-level warning when arguments fallback to {} (no longer silent)
- Type toolCall parameter as ToolCall instead of any in executeSpecificTool
and executeWildcardTool
- Both specific-tool and wildcard paths share the same parsing logic
Treat empty, null, or undefined tool arguments as {} instead of throwing
a JSON parse error. Uses explicit checks (=== '' || === null || === undefined)
rather than a broad falsy check, as recommended in review.
Addresses all review feedback from jpr5:
- Added tests for wildcard tool path with empty args
- Added tests for null and undefined arguments
- Used explicit empty/null/undefined check instead of broad falsy
- Added inline comments explaining the fallback rationale
- Removed duplicate tests (TEST 7/8) from core-full.test.ts
- Removed console.log debugging statements from tests
Run prettier on ~1,865 files across examples/ to match the monorepo's
formatting standards. These files were imported as-is from standalone
repos that used different prettier configs.
- base-command: wrap checkCLIVersion() fetch in try-catch so CLI
doesn't crash when offline (version check is non-critical)
- init: forward argv to Create instead of dropping all flags, remove
misleading flag definitions (init is just a deprecated redirect)
- detect-endpoint-type: fix Promise.all destructuring (5 promises but
only 4 variables caused isCopilot to receive the LangGraph FastAPI
result), add missing isMCP branch, use isLangGraphFastAPI result
- auth.service: validate OAuth state parameter before tracking analytics
with user data, add reject()+server.close() on state mismatch so the
Promise settles instead of hanging the CLI forever
- create.test: fix quote-style assertion to match prettier output
- Remove copy-paste triplication in scaffoldAgent (LangSmith block
duplicated twice, causing duplicate .env entries and redundant writes)
- Update AgentTemplates URLs to point to monorepo paths instead of
archived standalone repos
- Fix flags.projectName → args.projectName in banner logic (projectName
is an Args field, not Flags)
- Remove stale trpc-cli path mapping and project reference from
tsconfig.json (package doesn't exist in this monorepo)
Migrate the copilotkit CLI (npx copilotkit create/init/dev) from
CopilotCloud into packages/v1/cli. TEMPLATE_REPOS updated to use
monorepo subdirectory sparse checkout for all CopilotKit-owned
templates, with tarball fallback for external repos (ag2).
Mark all publishable @copilotkitnext/* packages as deprecated in
package.json, pointing users to the @copilotkit/* equivalents.
V2 features will be available under the /v2 subpath.
Affected packages: shared, core, agent, angular, react, runtime,
sqlite-runner, web-inspector.
Remove throw on isArgumentError — matches main's behavior where parse
errors are emitted via subscribers and the run continues, rather than
crashing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a new `runTool()` method to `CopilotKitCore` that allows programmatic
execution of registered frontend tools without requiring an LLM turn. This
enables UI-driven tool invocations (e.g., button clicks triggering tool
handlers) while maintaining proper message history and subscriber notifications.
Key changes:
- Extract `executeToolHandler` helper from duplicated logic in
`executeSpecificTool` to share with `runTool`
- Add `runTool()` on `RunHandler` with tool/agent lookup, message creation,
handler execution, and optional follow-up support
- Add `TOOL_NOT_FOUND` and `AGENT_NOT_FOUND` error codes
- Add `CopilotKitCoreRunToolParams` and `CopilotKitCoreRunToolResult` types
- Add delegation method on `CopilotKitCore`
- Add 16 comprehensive tests covering all runTool behaviors
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Same fix as zod-regression — the mock was missing addHookRenderToolCall
and removeHookRenderToolCall methods.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The mock was missing addHookRenderToolCall/removeHookRenderToolCall methods
introduced by the separate hook vs prop render tool call storage refactor.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Address review feedback: remove `as ReactToolCallRenderer` cast in
useFrontendTool by guarding with `tool.parameters` check (matching
CopilotKitProvider's pattern). Remove unused ReactToolCallRenderer
imports from use-frontend-tool.tsx and use-render-tool.tsx.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add tests verifying:
- useFrontendTool render registrations survive StrictMode remount
- Hook and prop render entries coexist through StrictMode remount
- Hook render entries survive provider prop changes
- Update useRenderTool test mock to match new addHookRenderToolCall API
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CopilotKitProvider's didMountRef guard breaks under React Strict Mode:
refs persist across the simulated unmount/remount cycle, causing the
provider's setRenderToolCalls effect to overwrite registrations from
useFrontendTool and useRenderTool hooks.
Split render tool call storage in CopilotKitCoreReact into two layers:
- _renderToolCalls: prop-based entries (set by provider)
- _hookRenderToolCalls: hook-based entries (set by useFrontendTool/useRenderTool)
The renderToolCalls getter merges both with a cached result for
useSyncExternalStore referential stability. Provider and hooks can
never overwrite each other, eliminating the race by design.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>