Skip to content

Commit 0ad2c92

Browse files
authored
Implement state management (#15)
1 parent a5dcff6 commit 0ad2c92

38 files changed

+2283
-305
lines changed

PLAN.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Plan: Centralize render tool management in CopilotKitCoreReact
2+
3+
## Objective
4+
Finish moving `renderToolCalls` / `currentRenderToolCalls` handling from `CopilotKitProvider` state into `CopilotKitCoreReact`, letting React consumers react to core-managed updates while keeping the core API as-is.
5+
6+
## Remaining Workstreams
7+
1. **Provider refactor** – replace the provider’s `CopilotKitCore` instance with a single `CopilotKitCoreReact`, keep the static render list fixed from construction, and push dynamic renderer updates through `setRenderToolCalls`. Mirror updates into React by reusing the provider’s existing merge logic inside a lightweight subscription effect.
8+
2. **Hooks & utilities** – update `useFrontendTool`, `useHumanInTheLoop`, and related helpers to manage their merge bookkeeping locally and call `copilotkit.setRenderToolCalls` with the updated dynamic list.
9+
3. **Surface & docs** – adjust context types, tests, and documentation to reflect the new contract (no more `setCurrentRenderToolCalls`).
10+
4. **Validation** – run the focused provider/chat rendering test suites and spot-check wildcard & human-in-the-loop flows.
11+
12+
## Implementation Details
13+
- In `CopilotKitProvider`, instantiate `CopilotKitCoreReact` (instead of `CopilotKitCore`), replace the `useState` store with a `useEffect`-driven subscription that listens for `onRenderToolCallsChanged` and forces a re-render (e.g., via `useReducer`). Use memoized helpers to compute the dynamic list, call `copilotkit.setRenderToolCalls(dynamicList)` when it changes, and read the combined list directly from the core.
14+
- Update the context value to share `copilotkit`, the merged render list from the core, and any helper needed for hooks to compute their dynamic lists; drop `setCurrentRenderToolCalls` from the public surface.
15+
- Adjust hooks to pull the current dynamic list, perform their simple merge/replacement locally, and push the result back through `setRenderToolCalls`; ensure cleanup maintains historical renderers where required.
16+
- Refresh docs/tests to cover the new API surface and ensure wildcard precedence expectations still hold.
17+
- Validate with targeted unit/integration tests (e.g., `pnpm test --filter CopilotKitProvider`, chat rendering suites).

apps/docs/reference/copilotkit-provider.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ const devAgent = new HttpAgent({
113113

114114
### renderToolCalls
115115

116-
`ReactToolCallRender[]` **(optional)**
116+
`ReactToolCallRenderer[]` **(optional)**
117117

118118
A static list of components to render when specific tools are called. Enables visual feedback for tool execution.
119119

@@ -210,9 +210,9 @@ The provider makes a `CopilotKitContextValue` available to child components thro
210210
```typescript
211211
interface CopilotKitContextValue {
212212
copilotkit: CopilotKitCore;
213-
renderToolCalls: ReactToolCallRender<any>[];
214-
currentRenderToolCalls: ReactToolCallRender<unknown>[];
215-
setCurrentRenderToolCalls: React.Dispatch<React.SetStateAction<ReactToolCallRender<unknown>[]>>;
213+
renderToolCalls: ReactToolCallRenderer<any>[];
214+
currentRenderToolCalls: ReactToolCallRenderer<unknown>[];
215+
setCurrentRenderToolCalls: React.Dispatch<React.SetStateAction<ReactToolCallRenderer<unknown>[]>>;
216216
}
217217
```
218218

apps/docs/reference/use-copilotkit.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,20 @@ for interacting with CopilotKit programmatically.
4747

4848
### renderToolCalls
4949

50-
`ReactToolCallRender<any>[]`
50+
`ReactToolCallRenderer<any>[]`
5151

5252
An array of tool call render configurations defined at the provider level. These are used to render visual feedback when
5353
tools are executed.
5454

5555
### currentRenderToolCalls
5656

57-
`ReactToolCallRender<unknown>[]`
57+
`ReactToolCallRenderer<unknown>[]`
5858

5959
The current list of render tool calls, including both static configurations and dynamically registered ones.
6060

6161
### setCurrentRenderToolCalls
6262

63-
`React.Dispatch<React.SetStateAction<ReactToolCallRender<unknown>[]>>`
63+
`React.Dispatch<React.SetStateAction<ReactToolCallRenderer<unknown>[]>>`
6464

6565
A setter function to update the current render tool calls. Useful for dynamically adding or removing tool renderers.
6666

apps/docs/reference/use-render-tool-call.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,9 @@ The hook works with tool renderers defined at various levels:
140140
Renderers defined in `CopilotKitProvider`:
141141

142142
```tsx
143-
import { CopilotKitProvider, defineToolCallRender } from "@copilotkitnext/react";
143+
import { CopilotKitProvider, defineToolCallRenderer } from "@copilotkitnext/react";
144144

145-
const searchRenderer = defineToolCallRender({
145+
const searchRenderer = defineToolCallRenderer({
146146
name: "search",
147147
render: ({ args, status }) => <SearchDisplay {...args} status={status} />,
148148
});
@@ -180,7 +180,7 @@ function DynamicTool() {
180180
A fallback renderer for unmatched tools:
181181

182182
```tsx
183-
const wildcardRenderer = defineToolCallRender({
183+
const wildcardRenderer = defineToolCallRenderer({
184184
name: "*",
185185
render: ({ name, args, status }) => (
186186
<div className="unknown-tool">

apps/react/demo/src/app/api/copilotkit/[[...slug]]/route.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ const getModelConfig = () => {
1111
} else if (process.env.GOOGLE_API_KEY?.trim()) {
1212
return "google/gemini-2.5-pro";
1313
}
14-
throw new Error(
15-
"No API key found. Please set OPENAI_API_KEY, ANTHROPIC_API_KEY, or GOOGLE_API_KEY environment variable.",
16-
);
14+
// Default to OpenAI (will fail at runtime if no key is set)
15+
return "openai/gpt-4o";
1716
};
1817

1918
const agent = new BasicAgent({

apps/react/demo/src/app/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
CopilotChat,
66
CopilotKitProvider,
77
useFrontendTool,
8-
defineToolCallRender,
8+
defineToolCallRenderer,
99
useConfigureSuggestions,
1010
} from "@copilotkitnext/react";
1111
import { z } from "zod";
@@ -15,7 +15,7 @@ export const dynamic = "force-dynamic";
1515

1616
export default function Home() {
1717
// Define a wildcard renderer for any undefined tools
18-
const wildcardRenderer = defineToolCallRender({
18+
const wildcardRenderer = defineToolCallRenderer({
1919
name: "*",
2020
// No args needed for wildcard - defaults to z.any()
2121
render: ({ name, args, status }) => (

apps/react/demo/src/app/sidebar/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import {
44
CopilotKitProvider,
55
CopilotSidebar,
6-
defineToolCallRender,
6+
defineToolCallRenderer,
77
useConfigureSuggestions,
88
useFrontendTool,
99
} from "@copilotkitnext/react";
@@ -12,7 +12,7 @@ import { z } from "zod";
1212
export const dynamic = "force-dynamic";
1313

1414
export default function SidebarDemoPage() {
15-
const wildcardRenderer = defineToolCallRender({
15+
const wildcardRenderer = defineToolCallRenderer({
1616
name: "*",
1717
render: ({ name, args, status }) => (
1818
<div className="rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm text-slate-700 shadow-sm">

docs/REACT_API.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Creates and owns a `CopilotKitCore` instance that manages agents, frontend tools
1010
- `headers?: Record<string,string>` – request headers forwarded with runtime calls; default `{}`.
1111
- `properties?: Record<string,unknown>` – runtime metadata payload; default `{}`.
1212
- `agents?: Record<string, AbstractAgent>` – preinstantiated agents, keyed by id.
13-
- `renderToolCalls?: ReactToolCallRender[]` – static set of tool renderers. The provider expects a stable array identity; changing the structure logs a console error.
13+
- `renderToolCalls?: ReactToolCallRenderer[]` – static set of tool renderers. The provider expects a stable array identity; changing the structure logs a console error.
1414
- `frontendTools?: ReactFrontendTool[]` – static tool handlers defined up front. Like `renderToolCalls`, the array should be stable.
1515
- `humanInTheLoop?: ReactHumanInTheLoop[]` – declarative human-in-the-loop tool definitions. Each becomes both a tool handler and a tool call renderer.
1616

@@ -29,8 +29,8 @@ import { CopilotKitProvider } from "@copilotkitnext/react";
2929
### `useCopilotKit`
3030
Context hook that returns:
3131
- `copilotkit: CopilotKitCore` – the live core instance.
32-
- `renderToolCalls: ReactToolCallRender[]` – full render list derived from provider props.
33-
- `currentRenderToolCalls: ReactToolCallRender[]` – current stateful render list used by `useRenderToolCall`.
32+
- `renderToolCalls: ReactToolCallRenderer[]` – full render list derived from provider props.
33+
- `currentRenderToolCalls: ReactToolCallRenderer[]` – current stateful render list used by `useRenderToolCall`.
3434
- `setCurrentRenderToolCalls` – setter for augmenting renderers (used internally by tooling hooks).
3535

3636
The hook subscribes to runtime load events so components re-render if the core finishes loading or fails to load.

0 commit comments

Comments
 (0)