@copilotkitnext/react 0.0.8 → 0.0.9-alpha.1

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/index.mjs CHANGED
@@ -11,6 +11,7 @@ import { Plus, Settings2, Mic, ArrowUp, X, Check } from "lucide-react";
11
11
 
12
12
  // src/providers/CopilotChatConfigurationProvider.tsx
13
13
  import { createContext, useContext } from "react";
14
+ import { DEFAULT_AGENT_ID } from "@copilotkitnext/shared";
14
15
  import { jsx } from "react/jsx-runtime";
15
16
  var CopilotChatDefaultLabels = {
16
17
  chatInputPlaceholder: "Type a message...",
@@ -31,16 +32,20 @@ var CopilotChatDefaultLabels = {
31
32
  chatDisclaimerText: "AI can make mistakes. Please verify important information."
32
33
  };
33
34
  var CopilotChatConfiguration = createContext(null);
34
- var CopilotChatConfigurationProvider = ({ children, labels = {}, inputValue, onSubmitInput, onChangeInput }) => {
35
+ var CopilotChatConfigurationProvider = ({
36
+ children,
37
+ labels = {},
38
+ agentId,
39
+ threadId
40
+ }) => {
35
41
  const mergedLabels = {
36
42
  ...CopilotChatDefaultLabels,
37
43
  ...labels
38
44
  };
39
45
  const configurationValue = {
40
46
  labels: mergedLabels,
41
- inputValue,
42
- onSubmitInput,
43
- onChangeInput
47
+ agentId: agentId ?? DEFAULT_AGENT_ID,
48
+ threadId
44
49
  };
45
50
  return /* @__PURE__ */ jsx(CopilotChatConfiguration.Provider, { value: configurationValue, children });
46
51
  };
@@ -490,10 +495,14 @@ function CopilotChatInput({
490
495
  className,
491
496
  ...props
492
497
  }) {
493
- const { inputValue, onSubmitInput, onChangeInput } = useCopilotChatConfiguration();
494
- value ??= inputValue;
495
- onSubmitMessage ??= onSubmitInput;
496
- onChange ??= onChangeInput;
498
+ const isControlled = value !== void 0;
499
+ const [internalValue, setInternalValue] = useState(() => value ?? "");
500
+ useEffect2(() => {
501
+ if (!isControlled && value !== void 0) {
502
+ setInternalValue(value);
503
+ }
504
+ }, [isControlled, value]);
505
+ const resolvedValue = isControlled ? value ?? "" : internalValue;
497
506
  const inputRef = useRef2(null);
498
507
  const audioRecorderRef = useRef2(null);
499
508
  useEffect2(() => {
@@ -510,7 +519,11 @@ function CopilotChatInput({
510
519
  }
511
520
  }, [mode]);
512
521
  const handleChange = (e) => {
513
- onChange?.(e.target.value);
522
+ const nextValue = e.target.value;
523
+ if (!isControlled) {
524
+ setInternalValue(nextValue);
525
+ }
526
+ onChange?.(nextValue);
514
527
  };
515
528
  const handleKeyDown = (e) => {
516
529
  if (e.key === "Enter" && !e.shiftKey) {
@@ -519,17 +532,25 @@ function CopilotChatInput({
519
532
  }
520
533
  };
521
534
  const send = () => {
522
- const trimmed = value?.trim();
523
- if (trimmed) {
524
- onSubmitMessage?.(trimmed);
525
- if (inputRef.current) {
526
- inputRef.current.focus();
527
- }
535
+ if (!onSubmitMessage) {
536
+ return;
537
+ }
538
+ const trimmed = resolvedValue.trim();
539
+ if (!trimmed) {
540
+ return;
541
+ }
542
+ onSubmitMessage(trimmed);
543
+ if (!isControlled) {
544
+ setInternalValue("");
545
+ onChange?.("");
546
+ }
547
+ if (inputRef.current) {
548
+ inputRef.current.focus();
528
549
  }
529
550
  };
530
551
  const BoundTextArea = renderSlot(textArea, CopilotChatInput.TextArea, {
531
552
  ref: inputRef,
532
- value,
553
+ value: resolvedValue,
533
554
  onChange: handleChange,
534
555
  onKeyDown: handleKeyDown,
535
556
  autoFocus
@@ -543,7 +564,7 @@ function CopilotChatInput({
543
564
  );
544
565
  const BoundSendButton = renderSlot(sendButton, CopilotChatInput.SendButton, {
545
566
  onClick: send,
546
- disabled: !value?.trim() || !onSubmitMessage
567
+ disabled: !resolvedValue.trim() || !onSubmitMessage
547
568
  });
548
569
  const BoundStartTranscribeButton = renderSlot(
549
570
  startTranscribeButton,
@@ -879,7 +900,7 @@ import "katex/dist/katex.min.css";
879
900
  import { completePartialMarkdown } from "@copilotkitnext/core";
880
901
 
881
902
  // src/hooks/use-render-tool-call.tsx
882
- import { useCallback } from "react";
903
+ import { useCallback, useEffect as useEffect4, useState as useState3 } from "react";
883
904
  import { ToolCallStatus } from "@copilotkitnext/core";
884
905
 
885
906
  // src/providers/CopilotKitProvider.tsx
@@ -892,6 +913,7 @@ import {
892
913
  useReducer,
893
914
  useRef as useRef3
894
915
  } from "react";
916
+ import { z } from "zod";
895
917
  import {
896
918
  CopilotKitCore
897
919
  } from "@copilotkitnext/core";
@@ -979,24 +1001,23 @@ var CopilotKitProvider = ({
979
1001
  return { tools: processedTools, renderToolCalls: processedRenderToolCalls };
980
1002
  }, [humanInTheLoopList]);
981
1003
  const allTools = useMemo(() => {
982
- const tools = {};
983
- frontendToolsList.forEach((tool) => {
984
- tools[tool.name] = tool;
985
- });
986
- processedHumanInTheLoopTools.tools.forEach((tool) => {
987
- tools[tool.name] = tool;
988
- });
1004
+ const tools = [];
1005
+ tools.push(...frontendToolsList);
1006
+ tools.push(...processedHumanInTheLoopTools.tools);
989
1007
  return tools;
990
1008
  }, [frontendToolsList, processedHumanInTheLoopTools]);
991
1009
  const allRenderToolCalls = useMemo(() => {
992
1010
  const combined = [...renderToolCallsList];
993
1011
  frontendToolsList.forEach((tool) => {
994
- if (tool.render && tool.parameters) {
995
- combined.push({
996
- name: tool.name,
997
- args: tool.parameters,
998
- render: tool.render
999
- });
1012
+ if (tool.render) {
1013
+ const args = tool.parameters || (tool.name === "*" ? z.any() : void 0);
1014
+ if (args) {
1015
+ combined.push({
1016
+ name: tool.name,
1017
+ args,
1018
+ render: tool.render
1019
+ });
1020
+ }
1000
1021
  }
1001
1022
  });
1002
1023
  combined.push(...processedHumanInTheLoopTools.renderToolCalls);
@@ -1015,9 +1036,30 @@ var CopilotKitProvider = ({
1015
1036
  return copilotkit2;
1016
1037
  }, [allTools]);
1017
1038
  useEffect3(() => {
1018
- setCurrentRenderToolCalls(
1019
- (prev) => prev === allRenderToolCalls ? prev : allRenderToolCalls
1020
- );
1039
+ setCurrentRenderToolCalls((prev) => {
1040
+ const keyOf = (rc) => `${rc?.agentId ?? ""}:${rc?.name ?? ""}`;
1041
+ const computedMap = /* @__PURE__ */ new Map();
1042
+ for (const rc of allRenderToolCalls) {
1043
+ computedMap.set(keyOf(rc), rc);
1044
+ }
1045
+ const merged = [...computedMap.values()];
1046
+ for (const rc of prev) {
1047
+ const k = keyOf(rc);
1048
+ if (!computedMap.has(k)) merged.push(rc);
1049
+ }
1050
+ const sameLength = merged.length === prev.length;
1051
+ if (sameLength) {
1052
+ let same = true;
1053
+ for (let i = 0; i < merged.length; i++) {
1054
+ if (merged[i] !== prev[i]) {
1055
+ same = false;
1056
+ break;
1057
+ }
1058
+ }
1059
+ if (same) return prev;
1060
+ }
1061
+ return merged;
1062
+ });
1021
1063
  }, [allRenderToolCalls]);
1022
1064
  useEffect3(() => {
1023
1065
  copilotkit.setRuntimeUrl(runtimeUrl);
@@ -1046,10 +1088,7 @@ var useCopilotKit = () => {
1046
1088
  }
1047
1089
  useEffect3(() => {
1048
1090
  const unsubscribe = context.copilotkit.subscribe({
1049
- onRuntimeLoaded: () => {
1050
- forceUpdate();
1051
- },
1052
- onRuntimeLoadError: () => {
1091
+ onRuntimeConnectionStatusChanged: () => {
1053
1092
  forceUpdate();
1054
1093
  }
1055
1094
  });
@@ -1064,35 +1103,73 @@ var useCopilotKit = () => {
1064
1103
  import { partialJSONParse } from "@copilotkitnext/shared";
1065
1104
  import { jsx as jsx8 } from "react/jsx-runtime";
1066
1105
  function useRenderToolCall() {
1067
- const { currentRenderToolCalls } = useCopilotKit();
1106
+ const { currentRenderToolCalls, copilotkit } = useCopilotKit();
1107
+ const { agentId } = useCopilotChatConfiguration();
1108
+ const [executingToolCallIds, setExecutingToolCallIds] = useState3(() => /* @__PURE__ */ new Set());
1109
+ useEffect4(() => {
1110
+ const unsubscribe = copilotkit.subscribe({
1111
+ onToolExecutionStart: ({ toolCallId }) => {
1112
+ setExecutingToolCallIds((prev) => {
1113
+ if (prev.has(toolCallId)) return prev;
1114
+ const next = new Set(prev);
1115
+ next.add(toolCallId);
1116
+ return next;
1117
+ });
1118
+ },
1119
+ onToolExecutionEnd: ({ toolCallId }) => {
1120
+ setExecutingToolCallIds((prev) => {
1121
+ if (!prev.has(toolCallId)) return prev;
1122
+ const next = new Set(prev);
1123
+ next.delete(toolCallId);
1124
+ return next;
1125
+ });
1126
+ }
1127
+ });
1128
+ return () => unsubscribe();
1129
+ }, [copilotkit]);
1068
1130
  const renderToolCall = useCallback(
1069
1131
  ({
1070
1132
  toolCall,
1071
1133
  toolMessage,
1072
- isLoading
1134
+ isRunning
1073
1135
  }) => {
1074
- const renderConfig = currentRenderToolCalls.find(
1136
+ const exactMatches = currentRenderToolCalls.filter(
1075
1137
  (rc) => rc.name === toolCall.function.name
1076
- ) || currentRenderToolCalls.find((rc) => rc.name === "*");
1138
+ );
1139
+ const renderConfig = exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || currentRenderToolCalls.find((rc) => rc.name === "*");
1077
1140
  if (!renderConfig) {
1078
1141
  return null;
1079
1142
  }
1080
1143
  const RenderComponent = renderConfig.render;
1081
1144
  const args = partialJSONParse(toolCall.function.arguments);
1145
+ const toolName = toolCall.function.name;
1082
1146
  if (toolMessage) {
1083
1147
  return /* @__PURE__ */ jsx8(
1084
1148
  RenderComponent,
1085
1149
  {
1150
+ name: toolName,
1086
1151
  args,
1087
1152
  status: ToolCallStatus.Complete,
1088
1153
  result: toolMessage.content
1089
1154
  },
1090
1155
  toolCall.id
1091
1156
  );
1092
- } else if (isLoading) {
1157
+ } else if (executingToolCallIds.has(toolCall.id)) {
1093
1158
  return /* @__PURE__ */ jsx8(
1094
1159
  RenderComponent,
1095
1160
  {
1161
+ name: toolName,
1162
+ args,
1163
+ status: ToolCallStatus.Executing,
1164
+ result: void 0
1165
+ },
1166
+ toolCall.id
1167
+ );
1168
+ } else if (isRunning) {
1169
+ return /* @__PURE__ */ jsx8(
1170
+ RenderComponent,
1171
+ {
1172
+ name: toolName,
1096
1173
  args,
1097
1174
  status: ToolCallStatus.InProgress,
1098
1175
  result: void 0
@@ -1103,6 +1180,7 @@ function useRenderToolCall() {
1103
1180
  return /* @__PURE__ */ jsx8(
1104
1181
  RenderComponent,
1105
1182
  {
1183
+ name: toolName,
1106
1184
  args,
1107
1185
  status: ToolCallStatus.Complete,
1108
1186
  result: ""
@@ -1111,54 +1189,57 @@ function useRenderToolCall() {
1111
1189
  );
1112
1190
  }
1113
1191
  },
1114
- [currentRenderToolCalls]
1192
+ [currentRenderToolCalls, executingToolCallIds, agentId]
1115
1193
  );
1116
1194
  return renderToolCall;
1117
1195
  }
1118
1196
 
1119
1197
  // src/hooks/use-frontend-tool.tsx
1120
- import { useEffect as useEffect4 } from "react";
1198
+ import { useEffect as useEffect5 } from "react";
1121
1199
  function useFrontendTool(tool) {
1122
- const { renderToolCalls, copilotkit, setCurrentRenderToolCalls } = useCopilotKit();
1123
- useEffect4(() => {
1124
- if (tool.name in copilotkit.tools) {
1200
+ const { copilotkit, setCurrentRenderToolCalls } = useCopilotKit();
1201
+ useEffect5(() => {
1202
+ const name = tool.name;
1203
+ if (copilotkit.getTool({ toolName: name, agentId: tool.agentId })) {
1125
1204
  console.warn(
1126
- `Tool '${tool.name}' already exists. It will be overridden.`
1205
+ `Tool '${name}' already exists for agent '${tool.agentId || "global"}'. Overriding with latest registration.`
1127
1206
  );
1207
+ copilotkit.removeTool(name, tool.agentId);
1128
1208
  }
1129
1209
  copilotkit.addTool(tool);
1130
- if (tool.render && tool.name in renderToolCalls) {
1131
- console.warn(
1132
- `Render component for tool '${tool.name}' already exists. It will be overridden.`
1133
- );
1134
- }
1135
- if (tool.render && tool.parameters) {
1136
- setCurrentRenderToolCalls((prev) => [
1137
- ...prev,
1138
- {
1139
- name: tool.name,
1140
- args: tool.parameters,
1141
- render: tool.render
1142
- }
1143
- ]);
1210
+ if (tool.render) {
1211
+ setCurrentRenderToolCalls((prev) => {
1212
+ const replaced = prev.filter(
1213
+ (rc) => !(rc.name === name && rc.agentId === tool.agentId)
1214
+ );
1215
+ return [
1216
+ ...replaced,
1217
+ {
1218
+ name,
1219
+ args: tool.parameters,
1220
+ agentId: tool.agentId,
1221
+ render: tool.render
1222
+ }
1223
+ ];
1224
+ });
1144
1225
  }
1145
1226
  return () => {
1146
- copilotkit.removeTool(tool.name);
1147
- setCurrentRenderToolCalls(
1148
- (prev) => prev.filter((rc) => rc.name !== tool.name)
1149
- );
1227
+ copilotkit.removeTool(name, tool.agentId);
1150
1228
  };
1151
- }, [tool, copilotkit, renderToolCalls, setCurrentRenderToolCalls]);
1229
+ }, [tool.name, copilotkit, setCurrentRenderToolCalls]);
1152
1230
  }
1153
1231
 
1154
1232
  // src/hooks/use-human-in-the-loop.tsx
1155
- import { useState as useState3, useCallback as useCallback2, useRef as useRef4 } from "react";
1233
+ import { useState as useState4, useCallback as useCallback2, useRef as useRef4, useEffect as useEffect6 } from "react";
1156
1234
  import React6 from "react";
1157
1235
  function useHumanInTheLoop(tool) {
1158
- const [status, setStatus] = useState3(
1236
+ const [status, setStatus] = useState4(
1159
1237
  "inProgress"
1160
1238
  );
1239
+ const statusRef = useRef4(status);
1161
1240
  const resolvePromiseRef = useRef4(null);
1241
+ const { setCurrentRenderToolCalls } = useCopilotKit();
1242
+ statusRef.current = status;
1162
1243
  const respond = useCallback2(async (result) => {
1163
1244
  if (resolvePromiseRef.current) {
1164
1245
  resolvePromiseRef.current(result);
@@ -1175,7 +1256,8 @@ function useHumanInTheLoop(tool) {
1175
1256
  const RenderComponent = useCallback2(
1176
1257
  (props) => {
1177
1258
  const ToolComponent = tool.render;
1178
- if (status === "inProgress" && props.status === "inProgress") {
1259
+ const currentStatus = statusRef.current;
1260
+ if (currentStatus === "inProgress" && props.status === "inProgress") {
1179
1261
  const enhancedProps = {
1180
1262
  ...props,
1181
1263
  name: tool.name,
@@ -1183,7 +1265,7 @@ function useHumanInTheLoop(tool) {
1183
1265
  respond: void 0
1184
1266
  };
1185
1267
  return React6.createElement(ToolComponent, enhancedProps);
1186
- } else if (status === "executing" && props.status === "executing") {
1268
+ } else if (currentStatus === "executing" && props.status === "executing") {
1187
1269
  const enhancedProps = {
1188
1270
  ...props,
1189
1271
  name: tool.name,
@@ -1191,7 +1273,7 @@ function useHumanInTheLoop(tool) {
1191
1273
  respond
1192
1274
  };
1193
1275
  return React6.createElement(ToolComponent, enhancedProps);
1194
- } else if (status === "complete" && props.status === "complete") {
1276
+ } else if (currentStatus === "complete" && props.status === "complete") {
1195
1277
  const enhancedProps = {
1196
1278
  ...props,
1197
1279
  name: tool.name,
@@ -1202,7 +1284,7 @@ function useHumanInTheLoop(tool) {
1202
1284
  }
1203
1285
  return React6.createElement(ToolComponent, props);
1204
1286
  },
1205
- [tool.render, tool.name, tool.description, status, respond]
1287
+ [tool.render, tool.name, tool.description, respond]
1206
1288
  );
1207
1289
  const frontendTool = {
1208
1290
  ...tool,
@@ -1210,51 +1292,84 @@ function useHumanInTheLoop(tool) {
1210
1292
  render: RenderComponent
1211
1293
  };
1212
1294
  useFrontendTool(frontendTool);
1295
+ useEffect6(() => {
1296
+ return () => {
1297
+ setCurrentRenderToolCalls(
1298
+ (prev) => prev.filter(
1299
+ (rc) => rc.name !== tool.name || rc.agentId !== tool.agentId
1300
+ )
1301
+ );
1302
+ };
1303
+ }, [setCurrentRenderToolCalls, tool.name, tool.agentId]);
1213
1304
  }
1214
1305
 
1215
1306
  // src/hooks/use-agent.tsx
1216
- import { useMemo as useMemo2, useEffect as useEffect5, useReducer as useReducer2, useState as useState4 } from "react";
1217
- import { DEFAULT_AGENT_ID } from "@copilotkitnext/shared";
1218
- function useAgent({ agentId } = {}) {
1219
- agentId ??= DEFAULT_AGENT_ID;
1307
+ import { useMemo as useMemo2, useEffect as useEffect7, useReducer as useReducer2 } from "react";
1308
+ import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID2 } from "@copilotkitnext/shared";
1309
+ var ALL_UPDATES = [
1310
+ "OnMessagesChanged" /* OnMessagesChanged */,
1311
+ "OnStateChanged" /* OnStateChanged */,
1312
+ "OnRunStatusChanged" /* OnRunStatusChanged */
1313
+ ];
1314
+ function useAgent({ agentId, updates } = {}) {
1315
+ agentId ??= DEFAULT_AGENT_ID2;
1220
1316
  const { copilotkit } = useCopilotKit();
1221
1317
  const [, forceUpdate] = useReducer2((x) => x + 1, 0);
1222
- const [isRunning, setIsRunning] = useState4(false);
1318
+ const updateFlags = useMemo2(
1319
+ () => updates ?? ALL_UPDATES,
1320
+ [JSON.stringify(updates)]
1321
+ );
1223
1322
  const agent = useMemo2(() => {
1224
1323
  return copilotkit.getAgent(agentId);
1225
- }, [agentId, copilotkit.agents, copilotkit.didLoadRuntime, copilotkit]);
1226
- useEffect5(() => {
1227
- const subscription = agent?.subscribe({
1228
- onMessagesChanged() {
1324
+ }, [
1325
+ agentId,
1326
+ copilotkit.agents,
1327
+ copilotkit.runtimeConnectionStatus,
1328
+ copilotkit
1329
+ ]);
1330
+ useEffect7(() => {
1331
+ if (!agent) {
1332
+ return;
1333
+ }
1334
+ if (updateFlags.length === 0) {
1335
+ return;
1336
+ }
1337
+ const handlers = {};
1338
+ if (updateFlags.includes("OnMessagesChanged" /* OnMessagesChanged */)) {
1339
+ handlers.onMessagesChanged = () => {
1229
1340
  forceUpdate();
1230
- },
1231
- onStateChanged() {
1341
+ };
1342
+ }
1343
+ if (updateFlags.includes("OnStateChanged" /* OnStateChanged */)) {
1344
+ handlers.onStateChanged = () => {
1232
1345
  forceUpdate();
1233
- },
1234
- onRunInitialized() {
1235
- setIsRunning(true);
1236
- },
1237
- onRunFinalized() {
1238
- setIsRunning(false);
1239
- },
1240
- onRunFailed() {
1241
- setIsRunning(false);
1242
- }
1243
- });
1244
- return () => subscription?.unsubscribe();
1245
- }, [agent]);
1346
+ };
1347
+ }
1348
+ if (updateFlags.includes("OnRunStatusChanged" /* OnRunStatusChanged */)) {
1349
+ handlers.onRunInitialized = () => {
1350
+ forceUpdate();
1351
+ };
1352
+ handlers.onRunFinalized = () => {
1353
+ forceUpdate();
1354
+ };
1355
+ handlers.onRunFailed = () => {
1356
+ forceUpdate();
1357
+ };
1358
+ }
1359
+ const subscription = agent.subscribe(handlers);
1360
+ return () => subscription.unsubscribe();
1361
+ }, [agent, forceUpdate, JSON.stringify(updateFlags)]);
1246
1362
  return {
1247
- agent,
1248
- isRunning
1363
+ agent
1249
1364
  };
1250
1365
  }
1251
1366
 
1252
1367
  // src/hooks/use-agent-context.tsx
1253
- import { useEffect as useEffect6 } from "react";
1368
+ import { useEffect as useEffect8 } from "react";
1254
1369
  function useAgentContext(context) {
1255
1370
  const { description, value } = context;
1256
1371
  const { copilotkit } = useCopilotKit();
1257
- useEffect6(() => {
1372
+ useEffect8(() => {
1258
1373
  if (!copilotkit) return;
1259
1374
  const id = copilotkit.addContext(context);
1260
1375
  return () => {
@@ -1269,7 +1384,7 @@ import { Fragment as Fragment2, jsx as jsx9 } from "react/jsx-runtime";
1269
1384
  function CopilotChatToolCallsView({
1270
1385
  message,
1271
1386
  messages = [],
1272
- isLoading = false
1387
+ isRunning = false
1273
1388
  }) {
1274
1389
  const renderToolCall = useRenderToolCall();
1275
1390
  if (!message.toolCalls || message.toolCalls.length === 0) {
@@ -1282,7 +1397,7 @@ function CopilotChatToolCallsView({
1282
1397
  return /* @__PURE__ */ jsx9(React7.Fragment, { children: renderToolCall({
1283
1398
  toolCall,
1284
1399
  toolMessage,
1285
- isLoading
1400
+ isRunning
1286
1401
  }) }, toolCall.id);
1287
1402
  }) });
1288
1403
  }
@@ -1293,7 +1408,7 @@ import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs4 } from "react/jsx-ru
1293
1408
  function CopilotChatAssistantMessage({
1294
1409
  message,
1295
1410
  messages,
1296
- isLoading,
1411
+ isRunning,
1297
1412
  onThumbsUp,
1298
1413
  onThumbsDown,
1299
1414
  onReadAloud,
@@ -1382,9 +1497,11 @@ function CopilotChatAssistantMessage({
1382
1497
  {
1383
1498
  message,
1384
1499
  messages,
1385
- isLoading
1500
+ isRunning
1386
1501
  }
1387
1502
  );
1503
+ const hasContent = !!(message.content && message.content.trim().length > 0);
1504
+ const shouldShowToolbar = toolbarVisible && hasContent;
1388
1505
  if (children) {
1389
1506
  return /* @__PURE__ */ jsx10(Fragment3, { children: children({
1390
1507
  markdownRenderer: boundMarkdownRenderer,
@@ -1397,13 +1514,13 @@ function CopilotChatAssistantMessage({
1397
1514
  regenerateButton: boundRegenerateButton,
1398
1515
  message,
1399
1516
  messages,
1400
- isLoading,
1517
+ isRunning,
1401
1518
  onThumbsUp,
1402
1519
  onThumbsDown,
1403
1520
  onReadAloud,
1404
1521
  onRegenerate,
1405
1522
  additionalToolbarItems,
1406
- toolbarVisible
1523
+ toolbarVisible: shouldShowToolbar
1407
1524
  }) });
1408
1525
  }
1409
1526
  return /* @__PURE__ */ jsxs4(
@@ -1418,7 +1535,7 @@ function CopilotChatAssistantMessage({
1418
1535
  children: [
1419
1536
  boundMarkdownRenderer,
1420
1537
  boundToolCallsView,
1421
- toolbarVisible && boundToolbar
1538
+ shouldShowToolbar && boundToolbar
1422
1539
  ]
1423
1540
  }
1424
1541
  );
@@ -1870,7 +1987,7 @@ function CopilotChatMessageView({
1870
1987
  assistantMessage,
1871
1988
  userMessage,
1872
1989
  cursor,
1873
- isLoading = false,
1990
+ isRunning = false,
1874
1991
  children,
1875
1992
  className,
1876
1993
  ...props
@@ -1881,7 +1998,7 @@ function CopilotChatMessageView({
1881
1998
  key: message.id,
1882
1999
  message,
1883
2000
  messages,
1884
- isLoading
2001
+ isRunning
1885
2002
  });
1886
2003
  } else if (message.role === "user") {
1887
2004
  return renderSlot(userMessage, CopilotChatUserMessage_default, {
@@ -1892,11 +2009,11 @@ function CopilotChatMessageView({
1892
2009
  return;
1893
2010
  }).filter(Boolean);
1894
2011
  if (children) {
1895
- return children({ messageElements, messages, isLoading });
2012
+ return children({ messageElements, messages, isRunning });
1896
2013
  }
1897
2014
  return /* @__PURE__ */ jsxs6("div", { className: twMerge6("flex flex-col", className), ...props, children: [
1898
2015
  messageElements,
1899
- isLoading && renderSlot(cursor, CopilotChatMessageView.Cursor, {})
2016
+ isRunning && renderSlot(cursor, CopilotChatMessageView.Cursor, {})
1900
2017
  ] });
1901
2018
  }
1902
2019
  CopilotChatMessageView.Cursor = function Cursor({
@@ -1917,7 +2034,7 @@ CopilotChatMessageView.Cursor = function Cursor({
1917
2034
  var CopilotChatMessageView_default = CopilotChatMessageView;
1918
2035
 
1919
2036
  // src/components/chat/CopilotChatView.tsx
1920
- import React8, { useRef as useRef5, useState as useState7, useEffect as useEffect7 } from "react";
2037
+ import React8, { useRef as useRef5, useState as useState7, useEffect as useEffect9 } from "react";
1921
2038
  import { twMerge as twMerge7 } from "tailwind-merge";
1922
2039
  import { StickToBottom, useStickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
1923
2040
  import { ChevronDown } from "lucide-react";
@@ -1932,6 +2049,8 @@ function CopilotChatView({
1932
2049
  disclaimer,
1933
2050
  messages = [],
1934
2051
  autoScroll = true,
2052
+ inputProps,
2053
+ isRunning = false,
1935
2054
  children,
1936
2055
  className,
1937
2056
  ...props
@@ -1940,7 +2059,7 @@ function CopilotChatView({
1940
2059
  const [inputContainerHeight, setInputContainerHeight] = useState7(0);
1941
2060
  const [isResizing, setIsResizing] = useState7(false);
1942
2061
  const resizeTimeoutRef = useRef5(null);
1943
- useEffect7(() => {
2062
+ useEffect9(() => {
1944
2063
  const element = inputContainerRef.current;
1945
2064
  if (!element) return;
1946
2065
  const resizeObserver = new ResizeObserver((entries) => {
@@ -1971,9 +2090,14 @@ function CopilotChatView({
1971
2090
  };
1972
2091
  }, []);
1973
2092
  const BoundMessageView = renderSlot(messageView, CopilotChatMessageView_default, {
1974
- messages
2093
+ messages,
2094
+ isRunning
1975
2095
  });
1976
- const BoundInput = renderSlot(input, CopilotChatInput_default, {});
2096
+ const BoundInput = renderSlot(
2097
+ input,
2098
+ CopilotChatInput_default,
2099
+ inputProps ?? {}
2100
+ );
1977
2101
  const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
1978
2102
  const BoundScrollView = renderSlot(scrollView, CopilotChatView.ScrollView, {
1979
2103
  autoScroll,
@@ -2055,10 +2179,10 @@ function CopilotChatView({
2055
2179
  const [hasMounted, setHasMounted] = useState7(false);
2056
2180
  const { scrollRef, contentRef, scrollToBottom } = useStickToBottom();
2057
2181
  const [showScrollButton, setShowScrollButton] = useState7(false);
2058
- useEffect7(() => {
2182
+ useEffect9(() => {
2059
2183
  setHasMounted(true);
2060
2184
  }, []);
2061
- useEffect7(() => {
2185
+ useEffect9(() => {
2062
2186
  if (autoScroll) return;
2063
2187
  const scrollElement = scrollRef.current;
2064
2188
  if (!scrollElement) return;
@@ -2191,83 +2315,101 @@ function CopilotChatView({
2191
2315
  var CopilotChatView_default = CopilotChatView;
2192
2316
 
2193
2317
  // src/components/chat/CopilotChat.tsx
2194
- import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID2, randomUUID } from "@copilotkitnext/shared";
2195
- import { useCallback as useCallback3, useState as useState8, useEffect as useEffect8, useMemo as useMemo3 } from "react";
2318
+ import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID3, randomUUID } from "@copilotkitnext/shared";
2319
+ import { useCallback as useCallback3, useEffect as useEffect10, useMemo as useMemo3 } from "react";
2196
2320
  import { merge } from "ts-deepmerge";
2321
+ import { AGUIConnectNotImplementedError } from "@ag-ui/client";
2197
2322
  import { jsx as jsx14 } from "react/jsx-runtime";
2198
2323
  function CopilotChat({
2199
- agentId = DEFAULT_AGENT_ID2,
2324
+ agentId = DEFAULT_AGENT_ID3,
2200
2325
  threadId,
2201
2326
  ...props
2202
2327
  }) {
2203
2328
  const { agent } = useAgent({ agentId });
2204
- const [isLoading, setIsLoading] = useState8(false);
2205
- threadId = threadId ?? useMemo3(() => randomUUID(), []);
2206
- const subscriber = {
2207
- onTextMessageStartEvent: () => setIsLoading(false),
2208
- onToolCallStartEvent: () => setIsLoading(false)
2209
- };
2210
- useEffect8(() => {
2211
- const connect = async () => {
2212
- setIsLoading(true);
2213
- await agent?.runAgent(
2214
- {
2215
- forwardedProps: { __copilotkitConnect: true }
2216
- },
2217
- subscriber
2218
- );
2219
- setIsLoading(false);
2329
+ const { copilotkit } = useCopilotKit();
2330
+ const resolvedThreadId = useMemo3(() => threadId ?? randomUUID(), [threadId]);
2331
+ useEffect10(() => {
2332
+ const connect = async (agent2) => {
2333
+ try {
2334
+ await copilotkit.connectAgent({ agent: agent2, agentId });
2335
+ } catch (error) {
2336
+ if (error instanceof AGUIConnectNotImplementedError) {
2337
+ } else {
2338
+ throw error;
2339
+ }
2340
+ }
2220
2341
  };
2221
2342
  if (agent) {
2222
- agent.threadId = threadId;
2223
- if ("isCopilotKitAgent" in agent) {
2224
- connect();
2225
- } else {
2226
- setIsLoading(false);
2227
- }
2343
+ agent.threadId = resolvedThreadId;
2344
+ connect(agent);
2228
2345
  }
2229
2346
  return () => {
2230
2347
  };
2231
- }, [threadId, agent]);
2232
- const [inputValue, setInputValue] = useState8("");
2348
+ }, [resolvedThreadId, agent, copilotkit, agentId]);
2233
2349
  const onSubmitInput = useCallback3(
2234
2350
  async (value) => {
2235
- setInputValue("");
2236
2351
  agent?.addMessage({
2237
2352
  id: randomUUID(),
2238
2353
  role: "user",
2239
2354
  content: value
2240
2355
  });
2241
- setIsLoading(true);
2242
- await agent?.runAgent({}, subscriber);
2243
- setIsLoading(false);
2356
+ if (agent) {
2357
+ try {
2358
+ await copilotkit.runAgent({ agent, agentId });
2359
+ } catch (error) {
2360
+ console.error("CopilotChat: runAgent failed", error);
2361
+ }
2362
+ }
2244
2363
  },
2245
- [agent]
2364
+ [agent, copilotkit, agentId]
2246
2365
  );
2366
+ const {
2367
+ inputProps: providedInputProps,
2368
+ messageView: providedMessageView,
2369
+ ...restProps
2370
+ } = props;
2247
2371
  const mergedProps = merge(
2248
2372
  {
2249
- messageView: { isLoading }
2373
+ isRunning: agent?.isRunning ?? false
2250
2374
  },
2251
2375
  {
2252
- ...props,
2253
- ...typeof props.messageView === "string" ? { messageView: { className: props.messageView } } : props.messageView !== void 0 ? { messageView: props.messageView } : {}
2376
+ ...restProps,
2377
+ ...typeof providedMessageView === "string" ? { messageView: { className: providedMessageView } } : providedMessageView !== void 0 ? { messageView: providedMessageView } : {}
2254
2378
  }
2255
2379
  );
2256
2380
  return /* @__PURE__ */ jsx14(
2257
2381
  CopilotChatConfigurationProvider,
2258
2382
  {
2259
- inputValue,
2260
- onSubmitInput,
2261
- onChangeInput: setInputValue,
2383
+ agentId,
2384
+ threadId: resolvedThreadId,
2262
2385
  children: /* @__PURE__ */ jsx14(
2263
2386
  CopilotChatView,
2264
2387
  {
2265
- ...{ messages: agent?.messages ?? [], ...mergedProps }
2388
+ ...{
2389
+ messages: agent?.messages ?? [],
2390
+ inputProps: {
2391
+ onSubmitMessage: onSubmitInput,
2392
+ ...providedInputProps
2393
+ },
2394
+ ...mergedProps
2395
+ }
2266
2396
  }
2267
2397
  )
2268
2398
  }
2269
2399
  );
2270
2400
  }
2401
+
2402
+ // src/types/defineToolCallRender.ts
2403
+ import { z as z2 } from "zod";
2404
+ function defineToolCallRender(def) {
2405
+ const argsSchema = def.name === "*" && !def.args ? z2.any() : def.args;
2406
+ return {
2407
+ name: def.name,
2408
+ args: argsSchema,
2409
+ render: def.render,
2410
+ ...def.agentId ? { agentId: def.agentId } : {}
2411
+ };
2412
+ }
2271
2413
  export {
2272
2414
  AudioRecorderError,
2273
2415
  CopilotChat,
@@ -2280,6 +2422,7 @@ export {
2280
2422
  CopilotChatUserMessage_default as CopilotChatUserMessage,
2281
2423
  CopilotChatView_default as CopilotChatView,
2282
2424
  CopilotKitProvider,
2425
+ defineToolCallRender,
2283
2426
  useAgent,
2284
2427
  useAgentContext,
2285
2428
  useCopilotChatConfiguration,