@copilotkit/react-core 1.56.4-canary.1777529757 → 1.56.4-canary.1777531098
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/dist/copilotkit-DFaI4j2r.d.mts.map +1 -1
- package/dist/{copilotkit-BAkj3zUc.cjs → copilotkit-DMFu29Kx.cjs} +26 -2
- package/dist/copilotkit-DMFu29Kx.cjs.map +1 -0
- package/dist/copilotkit-Dg4r4Gi_.d.cts.map +1 -1
- package/dist/{copilotkit-DAatqMh2.mjs → copilotkit-OmIUrWym.mjs} +26 -2
- package/dist/copilotkit-OmIUrWym.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +24 -0
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.mjs +1 -1
- package/dist/v2/index.umd.js +25 -1
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +6 -6
- package/src/v2/components/chat/CopilotChatView.tsx +13 -7
- package/src/v2/components/chat/__tests__/CopilotChat.suggestionsAlways.test.tsx +14 -20
- package/src/v2/hooks/use-configure-suggestions.tsx +43 -0
- package/dist/copilotkit-BAkj3zUc.cjs.map +0 -1
- package/dist/copilotkit-DAatqMh2.mjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@copilotkit/react-core",
|
|
3
|
-
"version": "1.56.4-canary.
|
|
3
|
+
"version": "1.56.4-canary.1777531098",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -73,11 +73,11 @@
|
|
|
73
73
|
"untruncate-json": "^0.0.1",
|
|
74
74
|
"use-stick-to-bottom": "^1.1.1",
|
|
75
75
|
"zod-to-json-schema": "^3.24.5",
|
|
76
|
-
"@copilotkit/a2ui-renderer": "1.56.4-canary.
|
|
77
|
-
"@copilotkit/
|
|
78
|
-
"@copilotkit/
|
|
79
|
-
"@copilotkit/runtime-client-gql": "1.56.4-canary.
|
|
80
|
-
"@copilotkit/core": "1.56.4-canary.
|
|
76
|
+
"@copilotkit/a2ui-renderer": "1.56.4-canary.1777531098",
|
|
77
|
+
"@copilotkit/web-inspector": "1.56.4-canary.1777531098",
|
|
78
|
+
"@copilotkit/shared": "1.56.4-canary.1777531098",
|
|
79
|
+
"@copilotkit/runtime-client-gql": "1.56.4-canary.1777531098",
|
|
80
|
+
"@copilotkit/core": "1.56.4-canary.1777531098"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
83
|
"@tailwindcss/cli": "^4.1.11",
|
|
@@ -264,14 +264,20 @@ export function CopilotChatView({
|
|
|
264
264
|
...(disclaimer !== undefined ? { disclaimer } : {}),
|
|
265
265
|
} as CopilotChatInputProps);
|
|
266
266
|
|
|
267
|
-
// Hide suggestions while a thread is connecting
|
|
268
|
-
//
|
|
269
|
-
//
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
267
|
+
// Hide suggestions while a thread is connecting or a run is in flight.
|
|
268
|
+
// Otherwise, mid-replay (bootstrap stream from /connect) or mid-run, the
|
|
269
|
+
// suggestions would render against a still-assembling message tree and
|
|
270
|
+
// visibly jump as each final text chunk reflows the layout.
|
|
271
|
+
//
|
|
272
|
+
// `available: "always"` controls *eligibility windows* (welcome screen vs
|
|
273
|
+
// after first message), not whether to render through these transitions —
|
|
274
|
+
// we still wait for the connect/run to settle and the end-of-run reload
|
|
275
|
+
// to repopulate against the new context.
|
|
273
276
|
const hasSuggestions =
|
|
274
|
-
!isConnecting &&
|
|
277
|
+
!isConnecting &&
|
|
278
|
+
!isRunning &&
|
|
279
|
+
Array.isArray(suggestions) &&
|
|
280
|
+
suggestions.length > 0;
|
|
275
281
|
const BoundSuggestionView = hasSuggestions
|
|
276
282
|
? renderSlot(suggestionView, CopilotChatSuggestionView, {
|
|
277
283
|
suggestions,
|
|
@@ -87,7 +87,7 @@ describe("CopilotChat - static suggestions with available:'always'", () => {
|
|
|
87
87
|
});
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
-
it("should
|
|
90
|
+
it("should hide suggestions during a run and restore them after", async () => {
|
|
91
91
|
const agent = new MockStepwiseAgent();
|
|
92
92
|
renderChat({ agent, consumerAgentId: "default" });
|
|
93
93
|
|
|
@@ -111,14 +111,13 @@ describe("CopilotChat - static suggestions with available:'always'", () => {
|
|
|
111
111
|
agent.emit(runStartedEvent());
|
|
112
112
|
agent.emit(textChunkEvent(messageId, "Hello! How can I help?"));
|
|
113
113
|
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
);
|
|
114
|
+
// While the run is in flight, suggestions should be hidden — every run
|
|
115
|
+
// changes the conversation context, so we wait for the end-of-run reload
|
|
116
|
+
// before showing them again.
|
|
117
|
+
await waitFor(() => {
|
|
118
|
+
expect(screen.queryByText("Say hello")).toBeNull();
|
|
119
|
+
expect(screen.queryByText("Get help")).toBeNull();
|
|
120
|
+
});
|
|
122
121
|
|
|
123
122
|
agent.emit(runFinishedEvent());
|
|
124
123
|
agent.complete();
|
|
@@ -127,7 +126,7 @@ describe("CopilotChat - static suggestions with available:'always'", () => {
|
|
|
127
126
|
expect(screen.getByText("Hello! How can I help?")).toBeDefined();
|
|
128
127
|
});
|
|
129
128
|
|
|
130
|
-
//
|
|
129
|
+
// After the run, the static "always" config repopulates them.
|
|
131
130
|
await waitFor(
|
|
132
131
|
() => {
|
|
133
132
|
expect(screen.getByText("Say hello")).toBeDefined();
|
|
@@ -137,7 +136,7 @@ describe("CopilotChat - static suggestions with available:'always'", () => {
|
|
|
137
136
|
);
|
|
138
137
|
});
|
|
139
138
|
|
|
140
|
-
it("should
|
|
139
|
+
it("should hide suggestions during a run in pin-to-send mode", async () => {
|
|
141
140
|
const agent = new MockStepwiseAgent();
|
|
142
141
|
renderChat({ agent, autoScroll: "pin-to-send" });
|
|
143
142
|
|
|
@@ -161,14 +160,10 @@ describe("CopilotChat - static suggestions with available:'always'", () => {
|
|
|
161
160
|
agent.emit(runStartedEvent());
|
|
162
161
|
agent.emit(textChunkEvent(messageId, "Hello! How can I help?"));
|
|
163
162
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
()
|
|
167
|
-
|
|
168
|
-
expect(screen.getByText("Get help")).toBeDefined();
|
|
169
|
-
},
|
|
170
|
-
{ timeout: 3000 },
|
|
171
|
-
);
|
|
163
|
+
await waitFor(() => {
|
|
164
|
+
expect(screen.queryByText("Say hello")).toBeNull();
|
|
165
|
+
expect(screen.queryByText("Get help")).toBeNull();
|
|
166
|
+
});
|
|
172
167
|
|
|
173
168
|
agent.emit(runFinishedEvent());
|
|
174
169
|
agent.complete();
|
|
@@ -177,7 +172,6 @@ describe("CopilotChat - static suggestions with available:'always'", () => {
|
|
|
177
172
|
expect(screen.getByText("Hello! How can I help?")).toBeDefined();
|
|
178
173
|
});
|
|
179
174
|
|
|
180
|
-
// And still visible after the run completes
|
|
181
175
|
await waitFor(
|
|
182
176
|
() => {
|
|
183
177
|
expect(screen.getByText("Say hello")).toBeDefined();
|
|
@@ -106,22 +106,37 @@ export function useConfigureSuggestions(
|
|
|
106
106
|
const isGlobalConfig =
|
|
107
107
|
rawConsumerAgentId === undefined || rawConsumerAgentId === "*";
|
|
108
108
|
|
|
109
|
+
const isDynamicConfigType = useMemo(
|
|
110
|
+
() => !!normalizedConfig && "instructions" in normalizedConfig,
|
|
111
|
+
[normalizedConfig],
|
|
112
|
+
);
|
|
113
|
+
|
|
109
114
|
const requestReload = useCallback(() => {
|
|
110
115
|
if (!normalizedConfig) {
|
|
111
116
|
return;
|
|
112
117
|
}
|
|
113
118
|
|
|
114
119
|
if (isGlobalConfig) {
|
|
120
|
+
const seen = new Set<string>();
|
|
115
121
|
const agents = Object.values(copilotkit.agents ?? {});
|
|
116
122
|
for (const entry of agents) {
|
|
117
123
|
const agentId = entry.agentId;
|
|
118
124
|
if (!agentId) {
|
|
119
125
|
continue;
|
|
120
126
|
}
|
|
127
|
+
seen.add(agentId);
|
|
121
128
|
if (!entry.isRunning) {
|
|
122
129
|
copilotkit.reloadSuggestions(agentId);
|
|
123
130
|
}
|
|
124
131
|
}
|
|
132
|
+
// Also reload for the chat's resolved consumer agent. The registry can
|
|
133
|
+
// be empty at this point (e.g. runtime info still loading), in which
|
|
134
|
+
// case the loop above wouldn't have fired for the agent the user is
|
|
135
|
+
// actually chatting with — and the welcome screen would render with
|
|
136
|
+
// no suggestions until they navigate away and back.
|
|
137
|
+
if (targetAgentId && !seen.has(targetAgentId)) {
|
|
138
|
+
copilotkit.reloadSuggestions(targetAgentId);
|
|
139
|
+
}
|
|
125
140
|
return;
|
|
126
141
|
}
|
|
127
142
|
|
|
@@ -169,6 +184,34 @@ export function useConfigureSuggestions(
|
|
|
169
184
|
}
|
|
170
185
|
requestReload();
|
|
171
186
|
}, [extraDeps.length, normalizedConfig, requestReload, ...extraDeps]);
|
|
187
|
+
|
|
188
|
+
// When agents arrive after the initial render (runtime info just landed),
|
|
189
|
+
// re-request a reload so dynamic configs that need a real agent can finally
|
|
190
|
+
// generate. Skip for static configs — they don't need an agent and the
|
|
191
|
+
// initial mount reload already handled them. Skip when the target agent
|
|
192
|
+
// is already in the registry — the initial reload already covered it, and
|
|
193
|
+
// re-firing on every subsequent `onAgentsChanged` (e.g. dev-mode hot
|
|
194
|
+
// reloads, sibling chat configs mounting) would stack overlapping
|
|
195
|
+
// generations.
|
|
196
|
+
useEffect(() => {
|
|
197
|
+
if (!normalizedConfig || !isDynamicConfigType) return;
|
|
198
|
+
if (!targetAgentId) return;
|
|
199
|
+
|
|
200
|
+
const initiallyPresent = !!copilotkit.getAgent(targetAgentId);
|
|
201
|
+
if (initiallyPresent) return;
|
|
202
|
+
|
|
203
|
+
const subscription = copilotkit.subscribe({
|
|
204
|
+
onAgentsChanged: () => {
|
|
205
|
+
if (copilotkit.getAgent(targetAgentId)) {
|
|
206
|
+
requestReload();
|
|
207
|
+
subscription.unsubscribe();
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
return () => {
|
|
212
|
+
subscription.unsubscribe();
|
|
213
|
+
};
|
|
214
|
+
}, [copilotkit, normalizedConfig, isDynamicConfigType, targetAgentId, requestReload]);
|
|
172
215
|
}
|
|
173
216
|
|
|
174
217
|
function isDynamicConfig(
|