@copilotkit/vue 1.59.1 → 1.59.2
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.cjs +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{use-render-activity-message-CE0GKV5B.js → use-render-activity-message-C6mweDb2.js} +1356 -1232
- package/dist/use-render-activity-message-C6mweDb2.js.map +1 -0
- package/dist/{use-render-activity-message-D7Ve-ASg.cjs → use-render-activity-message-CiFAWxYV.cjs} +18 -18
- package/dist/use-render-activity-message-CiFAWxYV.cjs.map +1 -0
- package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.mjs +1 -1
- package/package.json +4 -4
- package/src/v2/components/chat/CopilotChatMessageView.vue +1 -1
- package/src/v2/components/chat/__tests__/CopilotChat.e2e.test.ts +2 -2
- package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.ts +1 -1
- package/src/v2/components/chat/__tests__/CopilotChatMessageView.testid.spec.ts +17 -0
- package/src/v2/hooks/__tests__/use-default-render-tool.test.ts +374 -8
- package/src/v2/hooks/use-default-render-tool.ts +247 -59
- package/dist/use-render-activity-message-CE0GKV5B.js.map +0 -1
- package/dist/use-render-activity-message-D7Ve-ASg.cjs.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineComponent, h, ref } from "vue";
|
|
2
2
|
import type { WatchSource } from "vue";
|
|
3
3
|
import type { Component, VNodeChild } from "vue";
|
|
4
|
+
import { ToolCallStatus } from "@copilotkit/core";
|
|
4
5
|
import { useRenderTool } from "./use-render-tool";
|
|
5
6
|
|
|
6
7
|
type DefaultRenderProps = {
|
|
@@ -11,6 +12,98 @@ type DefaultRenderProps = {
|
|
|
11
12
|
result: string | undefined;
|
|
12
13
|
};
|
|
13
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Module-level dedup set so an unknown status value only emits a console
|
|
17
|
+
* warning the FIRST time we encounter it. Otherwise a stuck/unmapped status
|
|
18
|
+
* would log on every re-render (potentially many per second).
|
|
19
|
+
*/
|
|
20
|
+
const warnedUnknownStatuses = new Set<string>();
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Map a {@link ToolCallStatus} enum value to the documented string-union
|
|
24
|
+
* status the {@link DefaultRenderProps} contract exposes. Unknown / future
|
|
25
|
+
* enum members log a warning (once per distinct value) and fall back to
|
|
26
|
+
* `"inProgress"`.
|
|
27
|
+
*/
|
|
28
|
+
function mapToolCallStatus(
|
|
29
|
+
status: ToolCallStatus,
|
|
30
|
+
): DefaultRenderProps["status"] {
|
|
31
|
+
switch (status) {
|
|
32
|
+
case ToolCallStatus.Complete:
|
|
33
|
+
return "complete";
|
|
34
|
+
case ToolCallStatus.Executing:
|
|
35
|
+
return "executing";
|
|
36
|
+
case ToolCallStatus.InProgress:
|
|
37
|
+
return "inProgress";
|
|
38
|
+
default: {
|
|
39
|
+
const key = String(status);
|
|
40
|
+
if (!warnedUnknownStatuses.has(key)) {
|
|
41
|
+
warnedUnknownStatuses.add(key);
|
|
42
|
+
console.warn(
|
|
43
|
+
`[CopilotKit] Unknown ToolCallStatus "${key}" in default tool-call renderer; falling back to "inProgress".`,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return "inProgress";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Convert framework-internal raw renderer props (`args`, enum status) to the
|
|
53
|
+
* documented DefaultRenderProps shape. Idempotent on already-documented input
|
|
54
|
+
* — if the caller passes `parameters` and a string-union `status`, those win.
|
|
55
|
+
*/
|
|
56
|
+
type AdaptInput = {
|
|
57
|
+
name?: unknown;
|
|
58
|
+
toolCallId?: unknown;
|
|
59
|
+
args?: unknown;
|
|
60
|
+
parameters?: unknown;
|
|
61
|
+
status?: unknown;
|
|
62
|
+
result?: unknown;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function adaptRendererProps(raw: AdaptInput): DefaultRenderProps {
|
|
66
|
+
const parameters = raw.parameters !== undefined ? raw.parameters : raw.args;
|
|
67
|
+
const rawStatus = raw.status;
|
|
68
|
+
const status: DefaultRenderProps["status"] =
|
|
69
|
+
rawStatus === "inProgress" ||
|
|
70
|
+
rawStatus === "executing" ||
|
|
71
|
+
rawStatus === "complete"
|
|
72
|
+
? rawStatus
|
|
73
|
+
: mapToolCallStatus(rawStatus as ToolCallStatus);
|
|
74
|
+
return {
|
|
75
|
+
name: raw.name as string,
|
|
76
|
+
toolCallId: raw.toolCallId as string,
|
|
77
|
+
parameters,
|
|
78
|
+
status,
|
|
79
|
+
result: raw.result as string | undefined,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Guarded JSON.stringify for the expanded `<pre>` blocks. A circular reference
|
|
85
|
+
* would otherwise crash the Vue render.
|
|
86
|
+
*/
|
|
87
|
+
function safeStringifyForPre(value: unknown): string {
|
|
88
|
+
try {
|
|
89
|
+
return JSON.stringify(value, null, 2);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
console.warn(
|
|
92
|
+
"[CopilotKit] Failed to JSON.stringify tool-call payload for default renderer; falling back to String():",
|
|
93
|
+
err,
|
|
94
|
+
);
|
|
95
|
+
try {
|
|
96
|
+
return String(value);
|
|
97
|
+
} catch (innerErr) {
|
|
98
|
+
console.warn(
|
|
99
|
+
"[CopilotKit] safeStringifyForPre: value could not be stringified:",
|
|
100
|
+
innerErr,
|
|
101
|
+
);
|
|
102
|
+
return "[unserializable]";
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
14
107
|
const DefaultToolCallRenderer = defineComponent({
|
|
15
108
|
props: {
|
|
16
109
|
name: {
|
|
@@ -31,7 +124,11 @@ const DefaultToolCallRenderer = defineComponent({
|
|
|
31
124
|
required: true,
|
|
32
125
|
},
|
|
33
126
|
result: {
|
|
34
|
-
|
|
127
|
+
// Typeless on purpose: the renderer body handles both string results
|
|
128
|
+
// and structured (object) results via `safeStringifyForPre`. Declaring
|
|
129
|
+
// `type: String` would trip Vue's dev-mode prop-type warning on every
|
|
130
|
+
// non-string result and make the defensive branch unreachable.
|
|
131
|
+
type: null,
|
|
35
132
|
required: false,
|
|
36
133
|
default: undefined,
|
|
37
134
|
},
|
|
@@ -49,60 +146,114 @@ const DefaultToolCallRenderer = defineComponent({
|
|
|
49
146
|
? "Done"
|
|
50
147
|
: props.status;
|
|
51
148
|
|
|
52
|
-
return h(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
149
|
+
return h(
|
|
150
|
+
"div",
|
|
151
|
+
{
|
|
152
|
+
"data-testid": "copilot-tool-render",
|
|
153
|
+
"data-tool-name": props.name,
|
|
154
|
+
"data-tool-call-id": props.toolCallId,
|
|
155
|
+
"data-status": props.status,
|
|
156
|
+
"data-args": safeStringifyForAttr(props.parameters),
|
|
157
|
+
"data-result": safeStringifyForAttr(props.result),
|
|
158
|
+
style: { marginTop: "8px", paddingBottom: "8px" },
|
|
159
|
+
},
|
|
160
|
+
[
|
|
161
|
+
h(
|
|
162
|
+
"div",
|
|
163
|
+
{
|
|
164
|
+
style: {
|
|
165
|
+
borderRadius: "12px",
|
|
166
|
+
border: "1px solid #e4e4e7",
|
|
167
|
+
backgroundColor: "#fafafa",
|
|
168
|
+
padding: "14px 16px",
|
|
169
|
+
},
|
|
61
170
|
},
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
171
|
+
[
|
|
172
|
+
h(
|
|
173
|
+
"button",
|
|
174
|
+
{
|
|
175
|
+
type: "button",
|
|
176
|
+
"aria-expanded": String(isExpanded.value),
|
|
177
|
+
onClick: () => {
|
|
178
|
+
isExpanded.value = !isExpanded.value;
|
|
179
|
+
},
|
|
180
|
+
style: {
|
|
181
|
+
width: "100%",
|
|
182
|
+
display: "flex",
|
|
183
|
+
alignItems: "center",
|
|
184
|
+
justifyContent: "space-between",
|
|
185
|
+
gap: "10px",
|
|
186
|
+
cursor: "pointer",
|
|
187
|
+
border: "none",
|
|
188
|
+
padding: 0,
|
|
189
|
+
margin: 0,
|
|
190
|
+
background: "transparent",
|
|
191
|
+
textAlign: "left",
|
|
192
|
+
},
|
|
83
193
|
},
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
h(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
194
|
+
[
|
|
195
|
+
h(
|
|
196
|
+
"span",
|
|
197
|
+
{
|
|
198
|
+
"data-testid": "copilot-tool-render-name",
|
|
199
|
+
style: { fontWeight: "600" },
|
|
200
|
+
},
|
|
201
|
+
props.name,
|
|
202
|
+
),
|
|
203
|
+
h(
|
|
204
|
+
"span",
|
|
205
|
+
{ "data-testid": "copilot-tool-render-status" },
|
|
206
|
+
statusLabel,
|
|
207
|
+
),
|
|
208
|
+
],
|
|
209
|
+
),
|
|
210
|
+
isExpanded.value
|
|
211
|
+
? h("div", { style: { marginTop: "12px" } }, [
|
|
212
|
+
h("div", "Arguments"),
|
|
213
|
+
h("pre", safeStringifyForPre(props.parameters ?? {})),
|
|
214
|
+
props.result !== undefined
|
|
215
|
+
? h("div", [
|
|
216
|
+
h("div", "Result"),
|
|
217
|
+
h(
|
|
218
|
+
"pre",
|
|
219
|
+
typeof props.result === "string"
|
|
220
|
+
? props.result
|
|
221
|
+
: safeStringifyForPre(props.result),
|
|
222
|
+
),
|
|
223
|
+
])
|
|
224
|
+
: null,
|
|
225
|
+
])
|
|
226
|
+
: null,
|
|
227
|
+
],
|
|
228
|
+
),
|
|
229
|
+
],
|
|
230
|
+
);
|
|
102
231
|
};
|
|
103
232
|
},
|
|
104
233
|
});
|
|
105
234
|
|
|
235
|
+
function safeStringifyForAttr(value: unknown): string {
|
|
236
|
+
if (value === undefined || value === null) return "";
|
|
237
|
+
if (typeof value === "string") return value;
|
|
238
|
+
try {
|
|
239
|
+
return JSON.stringify(value);
|
|
240
|
+
} catch (err) {
|
|
241
|
+
console.warn(
|
|
242
|
+
"[CopilotKit] Failed to JSON.stringify tool-call payload for data-* attribute; falling back to String():",
|
|
243
|
+
err,
|
|
244
|
+
);
|
|
245
|
+
try {
|
|
246
|
+
return String(value);
|
|
247
|
+
} catch (innerErr) {
|
|
248
|
+
console.warn(
|
|
249
|
+
"[CopilotKit] safeStringifyForAttr: value could not be stringified:",
|
|
250
|
+
innerErr,
|
|
251
|
+
);
|
|
252
|
+
return "";
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
106
257
|
export function useDefaultRenderTool(
|
|
107
258
|
config?: {
|
|
108
259
|
render?:
|
|
@@ -111,19 +262,56 @@ export function useDefaultRenderTool(
|
|
|
111
262
|
},
|
|
112
263
|
deps?: WatchSource<unknown>[],
|
|
113
264
|
): void {
|
|
265
|
+
const userRender = config?.render;
|
|
266
|
+
|
|
267
|
+
// When the user supplies a function render, wrap it so they receive the
|
|
268
|
+
// documented {@link DefaultRenderProps} shape regardless of whether the
|
|
269
|
+
// call site passes `args + enum status` (CopilotChatToolCallsView's core
|
|
270
|
+
// path) or `parameters + string status` (an already-adapted call site).
|
|
271
|
+
// Component-typed renders are also wrapped — Vue would bind whatever attrs
|
|
272
|
+
// the call site passes, which means a component-typed render would receive
|
|
273
|
+
// the raw `{ args, status: <enum> }` shape instead of the documented
|
|
274
|
+
// `{ parameters, status: <string-union> }` shape. Wrap so the user
|
|
275
|
+
// component sees `DefaultRenderProps`.
|
|
276
|
+
let registeredRender:
|
|
277
|
+
| ((props: DefaultRenderProps) => VNodeChild)
|
|
278
|
+
| Component<DefaultRenderProps>;
|
|
279
|
+
|
|
280
|
+
if (typeof userRender === "function") {
|
|
281
|
+
const fn = userRender as (props: DefaultRenderProps) => VNodeChild;
|
|
282
|
+
registeredRender = ((rawProps: AdaptInput) => {
|
|
283
|
+
const adapted = adaptRendererProps(rawProps);
|
|
284
|
+
return fn(adapted);
|
|
285
|
+
}) as (props: DefaultRenderProps) => VNodeChild;
|
|
286
|
+
} else if (userRender) {
|
|
287
|
+
const userComponent = userRender;
|
|
288
|
+
registeredRender = ((rawProps: AdaptInput) => {
|
|
289
|
+
const adapted = adaptRendererProps(rawProps);
|
|
290
|
+
return h(userComponent as Component, {
|
|
291
|
+
name: adapted.name,
|
|
292
|
+
toolCallId: adapted.toolCallId,
|
|
293
|
+
parameters: adapted.parameters,
|
|
294
|
+
status: adapted.status,
|
|
295
|
+
result: adapted.result,
|
|
296
|
+
});
|
|
297
|
+
}) as (props: DefaultRenderProps) => VNodeChild;
|
|
298
|
+
} else {
|
|
299
|
+
registeredRender = ((rawProps: AdaptInput) => {
|
|
300
|
+
const adapted = adaptRendererProps(rawProps);
|
|
301
|
+
return h(DefaultToolCallRenderer, {
|
|
302
|
+
name: adapted.name,
|
|
303
|
+
toolCallId: adapted.toolCallId,
|
|
304
|
+
parameters: adapted.parameters,
|
|
305
|
+
status: adapted.status,
|
|
306
|
+
result: adapted.result,
|
|
307
|
+
});
|
|
308
|
+
}) as (props: DefaultRenderProps) => VNodeChild;
|
|
309
|
+
}
|
|
310
|
+
|
|
114
311
|
useRenderTool(
|
|
115
312
|
{
|
|
116
313
|
name: "*",
|
|
117
|
-
render:
|
|
118
|
-
config?.render ??
|
|
119
|
-
((props: DefaultRenderProps) =>
|
|
120
|
-
h(DefaultToolCallRenderer, {
|
|
121
|
-
name: props.name,
|
|
122
|
-
toolCallId: props.toolCallId,
|
|
123
|
-
parameters: props.parameters,
|
|
124
|
-
status: props.status,
|
|
125
|
-
result: props.result,
|
|
126
|
-
})),
|
|
314
|
+
render: registeredRender,
|
|
127
315
|
},
|
|
128
316
|
deps,
|
|
129
317
|
);
|