@copilotkit/react-core 1.50.0-beta.0 → 1.50.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +93 -0
- package/dist/{chunk-UJBV5GAG.mjs → chunk-3775VM7Y.mjs} +32 -65
- package/dist/chunk-3775VM7Y.mjs.map +1 -0
- package/dist/{chunk-3GURHDG7.mjs → chunk-4HRUQH6U.mjs} +3 -3
- package/dist/{chunk-7BYHZLPL.mjs → chunk-4RRMC7L2.mjs} +4 -4
- package/dist/chunk-4RRMC7L2.mjs.map +1 -0
- package/dist/{chunk-D3QSYDJR.mjs → chunk-7IBF6RBW.mjs} +2 -2
- package/dist/{chunk-GMI4KO4X.mjs → chunk-7SHWECGN.mjs} +2 -2
- package/dist/{chunk-OVYFRPSN.mjs → chunk-ABWT4DRT.mjs} +2 -2
- package/dist/{chunk-WVLHXIFP.mjs → chunk-AFNWX62Q.mjs} +2 -2
- package/dist/{chunk-WVLHXIFP.mjs.map → chunk-AFNWX62Q.mjs.map} +1 -1
- package/dist/{chunk-JRT5BJF3.mjs → chunk-B5ELMVT7.mjs} +2 -2
- package/dist/{chunk-TXI72QHK.mjs → chunk-EG56H77V.mjs} +2 -2
- package/dist/{chunk-DCHSCK62.mjs → chunk-FYMZKPOL.mjs} +36 -42
- package/dist/chunk-FYMZKPOL.mjs.map +1 -0
- package/dist/{chunk-FBD24VEH.mjs → chunk-HE22TZMF.mjs} +2 -2
- package/dist/{chunk-FBD24VEH.mjs.map → chunk-HE22TZMF.mjs.map} +1 -1
- package/dist/chunk-I76HKHPJ.mjs +32 -0
- package/dist/chunk-I76HKHPJ.mjs.map +1 -0
- package/dist/{chunk-LHKZJ2ND.mjs → chunk-PMWUKW3Z.mjs} +3 -3
- package/dist/{chunk-NROJOTQP.mjs → chunk-QNUAXSDP.mjs} +9 -6
- package/dist/chunk-QNUAXSDP.mjs.map +1 -0
- package/dist/{chunk-NG26QEGF.mjs → chunk-T2VBHAAP.mjs} +9 -3
- package/dist/chunk-T2VBHAAP.mjs.map +1 -0
- package/dist/{chunk-QU6NONOD.mjs → chunk-U2ZRVVKT.mjs} +2 -2
- package/dist/{chunk-R4MR43UQ.mjs → chunk-VV56AVPB.mjs} +33 -9
- package/dist/chunk-VV56AVPB.mjs.map +1 -0
- package/dist/{chunk-5X5DJRQQ.mjs → chunk-WF65O6HX.mjs} +2 -7
- package/dist/chunk-WF65O6HX.mjs.map +1 -0
- package/dist/chunk-XDFVCQD3.mjs +27 -0
- package/dist/chunk-XDFVCQD3.mjs.map +1 -0
- package/dist/{chunk-WMJVBMUX.mjs → chunk-YCG6SNAU.mjs} +2 -2
- package/dist/{chunk-3R423LZT.mjs → chunk-YJGPIN3R.mjs} +3 -3
- package/dist/{chunk-BR5YEYZJ.mjs → chunk-YTQHRJUA.mjs} +2 -2
- package/dist/chunk-Z6JV2LRY.mjs +37 -0
- package/dist/chunk-Z6JV2LRY.mjs.map +1 -0
- package/dist/{chunk-24SCZAB4.mjs → chunk-ZYTXB6HH.mjs} +22 -14
- package/dist/chunk-ZYTXB6HH.mjs.map +1 -0
- package/dist/components/CopilotListeners.js +13 -146
- package/dist/components/CopilotListeners.js.map +1 -1
- package/dist/components/CopilotListeners.mjs +1 -6
- package/dist/components/copilot-provider/copilot-messages.js +1 -1
- package/dist/components/copilot-provider/copilot-messages.js.map +1 -1
- package/dist/components/copilot-provider/copilot-messages.mjs +2 -2
- package/dist/components/copilot-provider/copilotkit-props.d.ts +1 -1
- package/dist/components/copilot-provider/copilotkit.d.ts +1 -1
- package/dist/components/copilot-provider/copilotkit.js +35 -40
- package/dist/components/copilot-provider/copilotkit.js.map +1 -1
- package/dist/components/copilot-provider/copilotkit.mjs +9 -9
- package/dist/components/copilot-provider/index.d.ts +1 -1
- package/dist/components/copilot-provider/index.js +35 -40
- package/dist/components/copilot-provider/index.js.map +1 -1
- package/dist/components/copilot-provider/index.mjs +9 -9
- package/dist/components/dev-console/console-trigger.js +1 -1
- package/dist/components/dev-console/console-trigger.js.map +1 -1
- package/dist/components/dev-console/console-trigger.mjs +3 -3
- package/dist/components/dev-console/developer-console-modal.js +1 -1
- package/dist/components/dev-console/developer-console-modal.js.map +1 -1
- package/dist/components/dev-console/developer-console-modal.mjs +2 -2
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +35 -40
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +9 -9
- package/dist/context/copilot-context.d.ts +1 -1
- package/dist/context/copilot-context.js +1 -1
- package/dist/context/copilot-context.js.map +1 -1
- package/dist/context/copilot-context.mjs +1 -1
- package/dist/context/index.d.ts +1 -1
- package/dist/context/index.js +1 -1
- package/dist/context/index.js.map +1 -1
- package/dist/context/index.mjs +1 -1
- package/dist/{copilot-context-1cd70a3f.d.ts → copilot-context-ec77e921.d.ts} +3 -3
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.js +254 -219
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +24 -23
- package/dist/hooks/use-agent-nodename.d.ts +3 -0
- package/dist/hooks/use-agent-nodename.js +56 -0
- package/dist/hooks/use-agent-nodename.js.map +1 -0
- package/dist/hooks/use-agent-nodename.mjs +8 -0
- package/dist/hooks/use-coagent-state-render-bridge.js +8 -5
- package/dist/hooks/use-coagent-state-render-bridge.js.map +1 -1
- package/dist/hooks/use-coagent-state-render-bridge.mjs +2 -2
- package/dist/hooks/use-coagent-state-render.js +1 -1
- package/dist/hooks/use-coagent-state-render.js.map +1 -1
- package/dist/hooks/use-coagent-state-render.mjs +2 -2
- package/dist/hooks/use-coagent.js +58 -21
- package/dist/hooks/use-coagent.js.map +1 -1
- package/dist/hooks/use-coagent.mjs +2 -1
- package/dist/hooks/use-copilot-action.js +5 -1
- package/dist/hooks/use-copilot-action.js.map +1 -1
- package/dist/hooks/use-copilot-action.mjs +2 -2
- package/dist/hooks/use-copilot-additional-instructions.js +1 -1
- package/dist/hooks/use-copilot-additional-instructions.js.map +1 -1
- package/dist/hooks/use-copilot-additional-instructions.mjs +2 -2
- package/dist/hooks/use-copilot-authenticated-action.js +6 -2
- package/dist/hooks/use-copilot-authenticated-action.js.map +1 -1
- package/dist/hooks/use-copilot-authenticated-action.mjs +4 -4
- package/dist/hooks/use-copilot-chat-headless_c.js +128 -140
- package/dist/hooks/use-copilot-chat-headless_c.js.map +1 -1
- package/dist/hooks/use-copilot-chat-headless_c.mjs +6 -6
- package/dist/hooks/{use-configure-chat-suggestions.d.ts → use-copilot-chat-suggestions.d.ts} +2 -3
- package/dist/hooks/use-copilot-chat-suggestions.js +60 -0
- package/dist/hooks/use-copilot-chat-suggestions.js.map +1 -0
- package/dist/hooks/use-copilot-chat-suggestions.mjs +8 -0
- package/dist/hooks/use-copilot-chat-suggestions.mjs.map +1 -0
- package/dist/hooks/use-copilot-chat.js +126 -138
- package/dist/hooks/use-copilot-chat.js.map +1 -1
- package/dist/hooks/use-copilot-chat.mjs +6 -6
- package/dist/hooks/use-copilot-chat_internal.d.ts +18 -1
- package/dist/hooks/use-copilot-chat_internal.js +126 -138
- package/dist/hooks/use-copilot-chat_internal.js.map +1 -1
- package/dist/hooks/use-copilot-chat_internal.mjs +5 -5
- package/dist/hooks/use-copilot-readable.d.ts +1 -1
- package/dist/hooks/use-copilot-readable.js +29 -5
- package/dist/hooks/use-copilot-readable.js.map +1 -1
- package/dist/hooks/use-copilot-readable.mjs +1 -1
- package/dist/hooks/use-default-tool.js +5 -1
- package/dist/hooks/use-default-tool.js.map +1 -1
- package/dist/hooks/use-default-tool.mjs +3 -3
- package/dist/hooks/use-frontend-tool.js +5 -1
- package/dist/hooks/use-frontend-tool.js.map +1 -1
- package/dist/hooks/use-frontend-tool.mjs +1 -1
- package/dist/hooks/use-langgraph-interrupt-render.js +77 -13
- package/dist/hooks/use-langgraph-interrupt-render.js.map +1 -1
- package/dist/hooks/use-langgraph-interrupt-render.mjs +3 -2
- package/dist/hooks/use-langgraph-interrupt.d.ts +1 -1
- package/dist/hooks/use-langgraph-interrupt.js +3 -3
- package/dist/hooks/use-langgraph-interrupt.js.map +1 -1
- package/dist/hooks/use-langgraph-interrupt.mjs +2 -2
- package/dist/hooks/use-make-copilot-document-readable.js +1 -1
- package/dist/hooks/use-make-copilot-document-readable.js.map +1 -1
- package/dist/hooks/use-make-copilot-document-readable.mjs +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +273 -246
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +34 -33
- package/dist/lib/copilot-task.d.ts +1 -1
- package/dist/lib/copilot-task.js.map +1 -1
- package/dist/lib/copilot-task.mjs +10 -10
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +10 -10
- package/dist/types/index.d.ts +1 -1
- package/dist/types/interrupt-action.d.ts +1 -1
- package/dist/types/interrupt-action.js.map +1 -1
- package/dist/utils/index.mjs +3 -3
- package/dist/v2/index.css +4 -0
- package/dist/v2/index.css.map +1 -0
- package/dist/v2/index.js.map +1 -1
- package/dist/v2/index.mjs +2 -0
- package/dist/v2/index.mjs.map +1 -1
- package/jest.config.js +12 -0
- package/package.json +27 -24
- package/src/components/CopilotListeners.tsx +1 -2
- package/src/components/copilot-provider/copilot-messages.tsx +0 -41
- package/src/components/copilot-provider/copilotkit.tsx +31 -31
- package/src/context/copilot-context.tsx +2 -2
- package/src/hooks/__tests__/use-coagent-config.test.ts +189 -129
- package/src/hooks/index.ts +2 -2
- package/src/hooks/use-agent-nodename.ts +30 -0
- package/src/hooks/use-coagent-state-render-bridge.tsx +22 -22
- package/src/hooks/use-coagent.ts +22 -13
- package/src/hooks/use-copilot-chat-suggestions.tsx +124 -0
- package/src/hooks/use-copilot-chat_internal.ts +78 -78
- package/src/hooks/use-copilot-readable.ts +30 -12
- package/src/hooks/use-frontend-tool.ts +10 -2
- package/src/hooks/use-langgraph-interrupt-render.ts +25 -7
- package/src/hooks/use-langgraph-interrupt.ts +2 -3
- package/src/types/interrupt-action.ts +2 -5
- package/src/v2/index.ts +2 -0
- package/tsup.config.ts +1 -1
- package/dist/chunk-24SCZAB4.mjs.map +0 -1
- package/dist/chunk-5X5DJRQQ.mjs.map +0 -1
- package/dist/chunk-7BYHZLPL.mjs.map +0 -1
- package/dist/chunk-CB7CRBDG.mjs +0 -48
- package/dist/chunk-CB7CRBDG.mjs.map +0 -1
- package/dist/chunk-DCHSCK62.mjs.map +0 -1
- package/dist/chunk-IUSKVYUI.mjs +0 -13
- package/dist/chunk-IUSKVYUI.mjs.map +0 -1
- package/dist/chunk-NG26QEGF.mjs.map +0 -1
- package/dist/chunk-NROJOTQP.mjs.map +0 -1
- package/dist/chunk-R4MR43UQ.mjs.map +0 -1
- package/dist/chunk-UJBV5GAG.mjs.map +0 -1
- package/dist/hooks/use-configure-chat-suggestions.js +0 -210
- package/dist/hooks/use-configure-chat-suggestions.js.map +0 -1
- package/dist/hooks/use-configure-chat-suggestions.mjs +0 -13
- package/src/hooks/use-configure-chat-suggestions.tsx +0 -85
- /package/dist/{chunk-3GURHDG7.mjs.map → chunk-4HRUQH6U.mjs.map} +0 -0
- /package/dist/{chunk-D3QSYDJR.mjs.map → chunk-7IBF6RBW.mjs.map} +0 -0
- /package/dist/{chunk-GMI4KO4X.mjs.map → chunk-7SHWECGN.mjs.map} +0 -0
- /package/dist/{chunk-OVYFRPSN.mjs.map → chunk-ABWT4DRT.mjs.map} +0 -0
- /package/dist/{chunk-JRT5BJF3.mjs.map → chunk-B5ELMVT7.mjs.map} +0 -0
- /package/dist/{chunk-TXI72QHK.mjs.map → chunk-EG56H77V.mjs.map} +0 -0
- /package/dist/{chunk-LHKZJ2ND.mjs.map → chunk-PMWUKW3Z.mjs.map} +0 -0
- /package/dist/{chunk-QU6NONOD.mjs.map → chunk-U2ZRVVKT.mjs.map} +0 -0
- /package/dist/{chunk-WMJVBMUX.mjs.map → chunk-YCG6SNAU.mjs.map} +0 -0
- /package/dist/{chunk-3R423LZT.mjs.map → chunk-YJGPIN3R.mjs.map} +0 -0
- /package/dist/{chunk-BR5YEYZJ.mjs.map → chunk-YTQHRJUA.mjs.map} +0 -0
- /package/dist/hooks/{use-configure-chat-suggestions.mjs.map → use-agent-nodename.mjs.map} +0 -0
- /package/src/v2/{styles.css → index.css} +0 -0
|
@@ -1,8 +1,43 @@
|
|
|
1
|
-
import { renderHook } from "@testing-library/react";
|
|
1
|
+
import { renderHook, waitFor } from "@testing-library/react";
|
|
2
2
|
import { useCoAgent } from "../use-coagent";
|
|
3
|
+
import type { AgentSubscriber } from "@ag-ui/client";
|
|
4
|
+
|
|
5
|
+
// Mock functions for @copilotkitnext/react
|
|
6
|
+
const mockSetState = jest.fn();
|
|
7
|
+
const mockRunAgent = jest.fn();
|
|
8
|
+
const mockAbortRun = jest.fn();
|
|
9
|
+
const mockSubscribe = jest.fn();
|
|
10
|
+
const mockSetProperties = jest.fn();
|
|
11
|
+
|
|
12
|
+
// Store the last subscriber for triggering events
|
|
13
|
+
let lastSubscriber: AgentSubscriber | null = null;
|
|
14
|
+
|
|
15
|
+
const mockAgent = {
|
|
16
|
+
agentId: "test-agent",
|
|
17
|
+
state: { count: 0 },
|
|
18
|
+
isRunning: false,
|
|
19
|
+
threadId: "thread-123",
|
|
20
|
+
setState: mockSetState,
|
|
21
|
+
runAgent: mockRunAgent,
|
|
22
|
+
abortRun: mockAbortRun,
|
|
23
|
+
subscribe: mockSubscribe.mockImplementation((subscriber: AgentSubscriber) => {
|
|
24
|
+
lastSubscriber = subscriber;
|
|
25
|
+
return {
|
|
26
|
+
unsubscribe: jest.fn(),
|
|
27
|
+
};
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
3
30
|
|
|
4
|
-
|
|
5
|
-
|
|
31
|
+
jest.mock("@copilotkitnext/react", () => ({
|
|
32
|
+
useAgent: jest.fn(() => ({ agent: mockAgent })),
|
|
33
|
+
useCopilotKit: jest.fn(() => ({
|
|
34
|
+
copilotkit: {
|
|
35
|
+
setProperties: mockSetProperties,
|
|
36
|
+
},
|
|
37
|
+
})),
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
// Mock other dependencies
|
|
6
41
|
const mockAppendMessage = jest.fn();
|
|
7
42
|
const mockRunChatCompletion = jest.fn();
|
|
8
43
|
|
|
@@ -27,7 +62,6 @@ jest.mock("../../context", () => ({
|
|
|
27
62
|
availableAgents: [],
|
|
28
63
|
coagentStates: {},
|
|
29
64
|
coagentStatesRef: { current: {} },
|
|
30
|
-
setCoagentStatesWithRef: mockSetCoagentStatesWithRef,
|
|
31
65
|
threadId: "test-thread",
|
|
32
66
|
copilotApiConfig: {
|
|
33
67
|
headers: {},
|
|
@@ -61,14 +95,10 @@ jest.mock("../../components/copilot-provider/copilot-messages", () => ({
|
|
|
61
95
|
describe("useCoAgent config synchronization", () => {
|
|
62
96
|
beforeEach(() => {
|
|
63
97
|
jest.clearAllMocks();
|
|
64
|
-
|
|
65
|
-
if (typeof updater === "function") {
|
|
66
|
-
updater({});
|
|
67
|
-
}
|
|
68
|
-
});
|
|
98
|
+
lastSubscriber = null;
|
|
69
99
|
});
|
|
70
100
|
|
|
71
|
-
it("should call
|
|
101
|
+
it("should call setProperties when config changes", async () => {
|
|
72
102
|
const { rerender } = renderHook(
|
|
73
103
|
({ config }) =>
|
|
74
104
|
useCoAgent({
|
|
@@ -82,16 +112,20 @@ describe("useCoAgent config synchronization", () => {
|
|
|
82
112
|
);
|
|
83
113
|
|
|
84
114
|
// Clear the initial calls
|
|
85
|
-
|
|
115
|
+
mockSetProperties.mockClear();
|
|
86
116
|
|
|
87
117
|
// Change config
|
|
88
118
|
rerender({ config: { configurable: { model: "gpt-4o" } } });
|
|
89
119
|
|
|
90
|
-
//
|
|
91
|
-
|
|
120
|
+
// Wait for effect to complete and verify setProperties was called
|
|
121
|
+
await waitFor(() => {
|
|
122
|
+
expect(mockSetProperties).toHaveBeenCalledWith({
|
|
123
|
+
configurable: { model: "gpt-4o" },
|
|
124
|
+
});
|
|
125
|
+
});
|
|
92
126
|
});
|
|
93
127
|
|
|
94
|
-
it("should not call
|
|
128
|
+
it("should not call setProperties when config is unchanged", () => {
|
|
95
129
|
const config = { configurable: { model: "gpt-4" } };
|
|
96
130
|
|
|
97
131
|
const { rerender } = renderHook(
|
|
@@ -107,16 +141,16 @@ describe("useCoAgent config synchronization", () => {
|
|
|
107
141
|
);
|
|
108
142
|
|
|
109
143
|
// Clear the initial calls
|
|
110
|
-
|
|
144
|
+
mockSetProperties.mockClear();
|
|
111
145
|
|
|
112
|
-
// Re-render with same config
|
|
146
|
+
// Re-render with same config reference
|
|
113
147
|
rerender({ config });
|
|
114
148
|
|
|
115
|
-
// Should not have called
|
|
116
|
-
expect(
|
|
149
|
+
// Should not have called setProperties
|
|
150
|
+
expect(mockSetProperties).not.toHaveBeenCalled();
|
|
117
151
|
});
|
|
118
152
|
|
|
119
|
-
it("should handle backward compatibility with configurable prop", () => {
|
|
153
|
+
it("should handle backward compatibility with configurable prop", async () => {
|
|
120
154
|
const { rerender } = renderHook(
|
|
121
155
|
({ configurable }) =>
|
|
122
156
|
useCoAgent({
|
|
@@ -130,23 +164,32 @@ describe("useCoAgent config synchronization", () => {
|
|
|
130
164
|
);
|
|
131
165
|
|
|
132
166
|
// Clear the initial calls
|
|
133
|
-
|
|
167
|
+
mockSetProperties.mockClear();
|
|
134
168
|
|
|
135
169
|
// Change configurable prop
|
|
136
170
|
rerender({ configurable: { model: "gpt-4o" } });
|
|
137
171
|
|
|
138
|
-
//
|
|
139
|
-
|
|
172
|
+
// Wait for effect to complete and verify setProperties was called
|
|
173
|
+
await waitFor(() => {
|
|
174
|
+
expect(mockSetProperties).toHaveBeenCalledWith({
|
|
175
|
+
configurable: { model: "gpt-4o" },
|
|
176
|
+
});
|
|
177
|
+
});
|
|
140
178
|
});
|
|
141
179
|
|
|
142
|
-
it("should
|
|
143
|
-
|
|
180
|
+
it("should not call setProperties when both config and configurable are undefined", () => {
|
|
181
|
+
renderHook(() =>
|
|
182
|
+
useCoAgent({
|
|
183
|
+
name: "test-agent",
|
|
184
|
+
initialState: { count: 0 },
|
|
185
|
+
}),
|
|
186
|
+
);
|
|
144
187
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
});
|
|
188
|
+
// Should not have called setProperties
|
|
189
|
+
expect(mockSetProperties).not.toHaveBeenCalled();
|
|
190
|
+
});
|
|
149
191
|
|
|
192
|
+
it("should handle deeply nested config changes", async () => {
|
|
150
193
|
const { rerender } = renderHook(
|
|
151
194
|
({ config }) =>
|
|
152
195
|
useCoAgent({
|
|
@@ -155,137 +198,154 @@ describe("useCoAgent config synchronization", () => {
|
|
|
155
198
|
config,
|
|
156
199
|
}),
|
|
157
200
|
{
|
|
158
|
-
initialProps: {
|
|
201
|
+
initialProps: {
|
|
202
|
+
config: {
|
|
203
|
+
configurable: {
|
|
204
|
+
model: "gpt-4",
|
|
205
|
+
settings: { temperature: 0.5 },
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
},
|
|
159
209
|
},
|
|
160
210
|
);
|
|
161
211
|
|
|
162
|
-
// Clear the initial calls
|
|
163
|
-
|
|
164
|
-
capturedUpdater = null;
|
|
165
|
-
|
|
166
|
-
// Change config
|
|
167
|
-
rerender({ config: { configurable: { model: "gpt-4o" } } });
|
|
168
|
-
|
|
169
|
-
// Should have called setCoagentStatesWithRef
|
|
170
|
-
expect(mockSetCoagentStatesWithRef).toHaveBeenCalledWith(expect.any(Function));
|
|
171
|
-
expect(capturedUpdater).toBeTruthy();
|
|
212
|
+
// Clear the initial calls
|
|
213
|
+
mockSetProperties.mockClear();
|
|
172
214
|
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
active: true,
|
|
181
|
-
threadId: "thread-123",
|
|
182
|
-
nodeName: "test-node",
|
|
183
|
-
runId: "run-456",
|
|
215
|
+
// Change nested config
|
|
216
|
+
rerender({
|
|
217
|
+
config: {
|
|
218
|
+
configurable: {
|
|
219
|
+
model: "gpt-4",
|
|
220
|
+
settings: { temperature: 0.7 }, // Only nested property changed
|
|
221
|
+
},
|
|
184
222
|
},
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
const newState = capturedUpdater(prevState);
|
|
223
|
+
});
|
|
188
224
|
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
threadId: "thread-123",
|
|
198
|
-
nodeName: "test-node",
|
|
199
|
-
runId: "run-456",
|
|
200
|
-
},
|
|
225
|
+
// Wait for effect to complete and verify setProperties was called
|
|
226
|
+
await waitFor(() => {
|
|
227
|
+
expect(mockSetProperties).toHaveBeenCalledWith({
|
|
228
|
+
configurable: {
|
|
229
|
+
model: "gpt-4",
|
|
230
|
+
settings: { temperature: 0.7 },
|
|
231
|
+
},
|
|
232
|
+
});
|
|
201
233
|
});
|
|
202
234
|
});
|
|
203
235
|
|
|
204
|
-
|
|
205
|
-
|
|
236
|
+
describe("State Management", () => {
|
|
237
|
+
// Helper to create mock subscriber params
|
|
238
|
+
const createMockParams = (stateOverride: any = {}) => ({
|
|
239
|
+
messages: [],
|
|
240
|
+
state: stateOverride,
|
|
241
|
+
agent: mockAgent as any,
|
|
242
|
+
input: {} as any,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("should initialize agent state via onRunInitialized event", () => {
|
|
246
|
+
// Set agent to have NO state (empty object)
|
|
247
|
+
mockAgent.state = {} as any;
|
|
248
|
+
|
|
249
|
+
renderHook(() =>
|
|
250
|
+
useCoAgent({
|
|
251
|
+
name: "test-agent",
|
|
252
|
+
initialState: { count: 42 },
|
|
253
|
+
}),
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
// Verify subscription was created
|
|
257
|
+
expect(mockSubscribe).toHaveBeenCalled();
|
|
258
|
+
expect(lastSubscriber).toBeTruthy();
|
|
259
|
+
|
|
260
|
+
// Clear any initial state calls
|
|
261
|
+
mockSetState.mockClear();
|
|
262
|
+
|
|
263
|
+
// Trigger onRunInitialized with no run state
|
|
264
|
+
lastSubscriber?.onRunInitialized?.(createMockParams({}));
|
|
265
|
+
|
|
266
|
+
// Should set state to initialState
|
|
267
|
+
expect(mockSetState).toHaveBeenCalledWith({ count: 42 });
|
|
206
268
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
return updater;
|
|
269
|
+
// Reset agent state
|
|
270
|
+
mockAgent.state = { count: 0 };
|
|
210
271
|
});
|
|
211
272
|
|
|
212
|
-
|
|
213
|
-
|
|
273
|
+
it("should preserve existing agent state on onRunInitialized", () => {
|
|
274
|
+
// Set agent to have existing state
|
|
275
|
+
mockAgent.state = { count: 100 };
|
|
276
|
+
|
|
277
|
+
renderHook(() =>
|
|
214
278
|
useCoAgent({
|
|
215
279
|
name: "test-agent",
|
|
216
|
-
initialState: { count:
|
|
217
|
-
config,
|
|
280
|
+
initialState: { count: 42 },
|
|
218
281
|
}),
|
|
219
|
-
|
|
220
|
-
initialProps: { config: { configurable: { model: "gpt-4" } } },
|
|
221
|
-
},
|
|
222
|
-
);
|
|
282
|
+
);
|
|
223
283
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
capturedUpdater = null;
|
|
284
|
+
// Clear any initial state calls
|
|
285
|
+
mockSetState.mockClear();
|
|
227
286
|
|
|
228
|
-
|
|
229
|
-
|
|
287
|
+
// Trigger onRunInitialized with no new state
|
|
288
|
+
lastSubscriber?.onRunInitialized?.(createMockParams({}));
|
|
289
|
+
|
|
290
|
+
// Should NOT override existing state
|
|
291
|
+
expect(mockSetState).not.toHaveBeenCalled();
|
|
292
|
+
|
|
293
|
+
// Reset agent state
|
|
294
|
+
mockAgent.state = { count: 0 };
|
|
295
|
+
});
|
|
230
296
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
297
|
+
it("should prioritize run state over initialState", () => {
|
|
298
|
+
renderHook(() =>
|
|
299
|
+
useCoAgent({
|
|
300
|
+
name: "test-agent",
|
|
301
|
+
initialState: { count: 42 },
|
|
302
|
+
}),
|
|
303
|
+
);
|
|
234
304
|
|
|
235
|
-
|
|
236
|
-
|
|
305
|
+
// Clear any initial state calls
|
|
306
|
+
mockSetState.mockClear();
|
|
237
307
|
|
|
238
|
-
|
|
308
|
+
// Trigger onRunInitialized with state from the run
|
|
309
|
+
lastSubscriber?.onRunInitialized?.(createMockParams({ count: 999 }));
|
|
239
310
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
"test-agent": {
|
|
243
|
-
name: "test-agent",
|
|
244
|
-
state: { count: 0 }, // Uses initialState
|
|
245
|
-
config: { configurable: { model: "gpt-4o" } }, // New config
|
|
246
|
-
running: false, // Default values
|
|
247
|
-
active: false,
|
|
248
|
-
threadId: undefined,
|
|
249
|
-
nodeName: undefined,
|
|
250
|
-
runId: undefined,
|
|
251
|
-
},
|
|
311
|
+
// Should use run state, not initialState
|
|
312
|
+
expect(mockSetState).toHaveBeenCalledWith({ count: 999 });
|
|
252
313
|
});
|
|
253
|
-
});
|
|
254
314
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
({ config }) =>
|
|
315
|
+
it("should handle setState with object updates", () => {
|
|
316
|
+
const { result } = renderHook(() =>
|
|
258
317
|
useCoAgent({
|
|
259
318
|
name: "test-agent",
|
|
260
319
|
initialState: { count: 0 },
|
|
261
|
-
config,
|
|
262
320
|
}),
|
|
263
|
-
|
|
264
|
-
initialProps: {
|
|
265
|
-
config: {
|
|
266
|
-
configurable: {
|
|
267
|
-
model: "gpt-4",
|
|
268
|
-
settings: { temperature: 0.5 },
|
|
269
|
-
},
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
},
|
|
273
|
-
);
|
|
321
|
+
);
|
|
274
322
|
|
|
275
|
-
|
|
276
|
-
|
|
323
|
+
// Update state with object
|
|
324
|
+
result.current.setState({ count: 5 });
|
|
277
325
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
config: {
|
|
281
|
-
configurable: {
|
|
282
|
-
model: "gpt-4",
|
|
283
|
-
settings: { temperature: 0.7 }, // Only nested property changed
|
|
284
|
-
},
|
|
285
|
-
},
|
|
326
|
+
// Should merge with existing state
|
|
327
|
+
expect(mockSetState).toHaveBeenCalledWith({ count: 5 });
|
|
286
328
|
});
|
|
287
329
|
|
|
288
|
-
|
|
289
|
-
|
|
330
|
+
it("should handle setState with function updaters", () => {
|
|
331
|
+
// Set current agent state
|
|
332
|
+
mockAgent.state = { count: 10 };
|
|
333
|
+
|
|
334
|
+
const { result } = renderHook(() =>
|
|
335
|
+
useCoAgent({
|
|
336
|
+
name: "test-agent",
|
|
337
|
+
initialState: { count: 0 },
|
|
338
|
+
}),
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
// Update state with function
|
|
342
|
+
result.current.setState((prev) => ({ count: (prev?.count || 0) + 5 }));
|
|
343
|
+
|
|
344
|
+
// Should call function with current state and set result
|
|
345
|
+
expect(mockSetState).toHaveBeenCalledWith({ count: 15 });
|
|
346
|
+
|
|
347
|
+
// Reset agent state
|
|
348
|
+
mockAgent.state = { count: 0 };
|
|
349
|
+
});
|
|
290
350
|
});
|
|
291
351
|
});
|
package/src/hooks/index.ts
CHANGED
|
@@ -24,6 +24,6 @@ export { useRenderToolCall } from "./use-render-tool-call";
|
|
|
24
24
|
export { useDefaultTool } from "./use-default-tool";
|
|
25
25
|
export { useLazyToolRenderer } from "./use-lazy-tool-renderer";
|
|
26
26
|
export {
|
|
27
|
-
|
|
27
|
+
useCopilotChatSuggestions,
|
|
28
28
|
type UseCopilotChatSuggestionsConfiguration,
|
|
29
|
-
} from "./use-
|
|
29
|
+
} from "./use-copilot-chat-suggestions";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import type { AgentSubscriber } from "@ag-ui/client";
|
|
3
|
+
import { useAgent } from "@copilotkitnext/react";
|
|
4
|
+
|
|
5
|
+
export function useAgentNodeName(agentName?: string) {
|
|
6
|
+
const { agent } = useAgent({ agentId: agentName });
|
|
7
|
+
const nodeNameRef = useRef<string>("start");
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (!agent) return;
|
|
11
|
+
const subscriber: AgentSubscriber = {
|
|
12
|
+
onStepStartedEvent: ({ event }) => {
|
|
13
|
+
nodeNameRef.current = event.stepName;
|
|
14
|
+
},
|
|
15
|
+
onRunStartedEvent: () => {
|
|
16
|
+
nodeNameRef.current = "start";
|
|
17
|
+
},
|
|
18
|
+
onRunFinishedEvent: () => {
|
|
19
|
+
nodeNameRef.current = "end";
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const subscription = agent.subscribe(subscriber);
|
|
24
|
+
return () => {
|
|
25
|
+
subscription.unsubscribe();
|
|
26
|
+
};
|
|
27
|
+
}, [agent]);
|
|
28
|
+
|
|
29
|
+
return nodeNameRef.current;
|
|
30
|
+
}
|
|
@@ -5,6 +5,7 @@ import { useCoAgentStateRenders } from "../context";
|
|
|
5
5
|
import { dataToUUID, parseJson } from "@copilotkit/shared";
|
|
6
6
|
|
|
7
7
|
function getStateWithoutConstantKeys(state: any) {
|
|
8
|
+
if (!state) return {};
|
|
8
9
|
const { messages, tools, copilotkit, ...stateWithoutConstantKeys } = state;
|
|
9
10
|
return stateWithoutConstantKeys;
|
|
10
11
|
}
|
|
@@ -148,23 +149,17 @@ export function useCoagentStateRenderBridge(agentId: string, props: CoAgentState
|
|
|
148
149
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
149
150
|
}, [agentId, nodeName]);
|
|
150
151
|
|
|
151
|
-
if (messageIndexInRun !== 0) {
|
|
152
|
-
return null;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
152
|
const getStateRender = useCallback(
|
|
156
153
|
(messageId: string) => {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
});
|
|
167
|
-
},
|
|
154
|
+
return Object.entries(coAgentStateRenders).find(([stateRenderId, stateRender]) => {
|
|
155
|
+
if (claimsRef.current[messageId]) {
|
|
156
|
+
return stateRenderId === claimsRef.current[messageId].stateRenderId;
|
|
157
|
+
}
|
|
158
|
+
const matchingAgentName = stateRender.name === agentId;
|
|
159
|
+
const matchesNodeContext = stateRender.nodeName ? stateRender.nodeName === nodeName : true;
|
|
160
|
+
return matchingAgentName && matchesNodeContext;
|
|
161
|
+
});
|
|
162
|
+
},
|
|
168
163
|
[coAgentStateRenders, nodeName, agentId],
|
|
169
164
|
);
|
|
170
165
|
|
|
@@ -200,8 +195,8 @@ export function useCoagentStateRenderBridge(agentId: string, props: CoAgentState
|
|
|
200
195
|
const renderClaimedByOtherMessage = Object.values(claimsRef.current).find(
|
|
201
196
|
(c) =>
|
|
202
197
|
c.stateRenderId === stateRenderId &&
|
|
203
|
-
dataToUUID(
|
|
204
|
-
dataToUUID(
|
|
198
|
+
dataToUUID(getStateWithoutConstantKeys(c.stateSnapshot)) ===
|
|
199
|
+
dataToUUID(getStateWithoutConstantKeys(renderSnapshot)),
|
|
205
200
|
);
|
|
206
201
|
if (renderClaimedByOtherMessage) {
|
|
207
202
|
// If:
|
|
@@ -228,6 +223,10 @@ export function useCoagentStateRenderBridge(agentId: string, props: CoAgentState
|
|
|
228
223
|
};
|
|
229
224
|
|
|
230
225
|
return useMemo(() => {
|
|
226
|
+
if (messageIndexInRun !== 0) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
|
|
231
230
|
const [stateRenderId, stateRender] = getStateRender(message.id) ?? [];
|
|
232
231
|
|
|
233
232
|
if (!stateRender || !stateRenderId) {
|
|
@@ -270,11 +269,11 @@ export function useCoagentStateRenderBridge(agentId: string, props: CoAgentState
|
|
|
270
269
|
|
|
271
270
|
if (typeof stateRender.render === "string") return stateRender.render;
|
|
272
271
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
272
|
+
return stateRender.render({
|
|
273
|
+
status,
|
|
274
|
+
// Always use state from claim, to make sure the state does not seem "wiped" for a fraction of a second
|
|
275
|
+
state: claimsRef.current[message.id].stateSnapshot ?? {},
|
|
276
|
+
nodeName: nodeName ?? "",
|
|
278
277
|
});
|
|
279
278
|
}
|
|
280
279
|
}, [
|
|
@@ -285,6 +284,7 @@ export function useCoagentStateRenderBridge(agentId: string, props: CoAgentState
|
|
|
285
284
|
nodeName,
|
|
286
285
|
effectiveRunId,
|
|
287
286
|
message.id,
|
|
287
|
+
messageIndexInRun,
|
|
288
288
|
]);
|
|
289
289
|
}
|
|
290
290
|
|
package/src/hooks/use-coagent.ts
CHANGED
|
@@ -90,8 +90,9 @@
|
|
|
90
90
|
|
|
91
91
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
92
92
|
import { Message } from "@copilotkit/shared";
|
|
93
|
-
import { useAgent } from "@copilotkitnext/react";
|
|
93
|
+
import { useAgent, useCopilotKit } from "@copilotkitnext/react";
|
|
94
94
|
import { type AgentSubscriber } from "@ag-ui/client";
|
|
95
|
+
import { useAgentNodeName } from "./use-agent-nodename";
|
|
95
96
|
|
|
96
97
|
interface UseCoagentOptionsBase {
|
|
97
98
|
/**
|
|
@@ -203,7 +204,8 @@ export type HintFunction = (params: HintFunctionParams) => Message | undefined;
|
|
|
203
204
|
*/
|
|
204
205
|
export function useCoAgent<T = any>(options: UseCoagentOptions<T>): UseCoagentReturnType<T> {
|
|
205
206
|
const { agent } = useAgent({ agentId: options.name });
|
|
206
|
-
const
|
|
207
|
+
const { copilotkit } = useCopilotKit();
|
|
208
|
+
const nodeName = useAgentNodeName(options.name);
|
|
207
209
|
|
|
208
210
|
const handleStateUpdate = useCallback(
|
|
209
211
|
(newState: T | ((prevState: T | undefined) => T)) => {
|
|
@@ -219,6 +221,22 @@ export function useCoAgent<T = any>(options: UseCoagentOptions<T>): UseCoagentRe
|
|
|
219
221
|
[agent?.state, agent?.setState],
|
|
220
222
|
);
|
|
221
223
|
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
if (!options.config && !options.configurable) return;
|
|
226
|
+
|
|
227
|
+
let config = options.config ?? {};
|
|
228
|
+
if (options.configurable) {
|
|
229
|
+
config = {
|
|
230
|
+
...config,
|
|
231
|
+
configurable: {
|
|
232
|
+
...options.configurable,
|
|
233
|
+
...config.configurable,
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
copilotkit.setProperties(config);
|
|
238
|
+
}, [options.config, options.configurable]);
|
|
239
|
+
|
|
222
240
|
const externalStateStr = useMemo(
|
|
223
241
|
() => (isExternalStateManagement(options) ? JSON.stringify(options.state) : undefined),
|
|
224
242
|
[isExternalStateManagement(options) ? JSON.stringify(options.state) : undefined],
|
|
@@ -284,15 +302,6 @@ export function useCoAgent<T = any>(options: UseCoagentOptions<T>): UseCoagentRe
|
|
|
284
302
|
handleStateUpdate(initialStateRef.current);
|
|
285
303
|
}
|
|
286
304
|
},
|
|
287
|
-
onStepStartedEvent: ({ event }) => {
|
|
288
|
-
nodeNameRef.current = event.stepName;
|
|
289
|
-
},
|
|
290
|
-
onRunStartedEvent: () => {
|
|
291
|
-
nodeNameRef.current = "start";
|
|
292
|
-
},
|
|
293
|
-
onRunFinishedEvent: () => {
|
|
294
|
-
nodeNameRef.current = "end";
|
|
295
|
-
},
|
|
296
305
|
};
|
|
297
306
|
|
|
298
307
|
const subscription = agent.subscribe(subscriber);
|
|
@@ -314,7 +323,7 @@ export function useCoAgent<T = any>(options: UseCoagentOptions<T>): UseCoagentRe
|
|
|
314
323
|
({} as T);
|
|
315
324
|
return {
|
|
316
325
|
name: options.name,
|
|
317
|
-
nodeName
|
|
326
|
+
nodeName,
|
|
318
327
|
threadId: undefined,
|
|
319
328
|
running: false,
|
|
320
329
|
state: initialState as T,
|
|
@@ -327,7 +336,7 @@ export function useCoAgent<T = any>(options: UseCoagentOptions<T>): UseCoagentRe
|
|
|
327
336
|
|
|
328
337
|
return {
|
|
329
338
|
name: agent?.agentId ?? options.name,
|
|
330
|
-
nodeName
|
|
339
|
+
nodeName,
|
|
331
340
|
threadId: agent.threadId,
|
|
332
341
|
running: agent.isRunning,
|
|
333
342
|
state: agent.state,
|