@cntyclub/agent-react 0.4.0 → 0.5.0
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/components/agent-panel.d.ts +3 -1
- package/dist/components/agent-panel.d.ts.map +1 -1
- package/dist/components/agent-widget.d.ts.map +1 -1
- package/dist/components/message-item.d.ts +5 -1
- package/dist/components/message-item.d.ts.map +1 -1
- package/dist/components/tool-activity-group.d.ts +15 -0
- package/dist/components/tool-activity-group.d.ts.map +1 -0
- package/dist/components/tool-approval-card.d.ts +10 -5
- package/dist/components/tool-approval-card.d.ts.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +353 -93
- package/dist/index.js.map +1 -1
- package/dist/message-group.d.ts +37 -0
- package/dist/message-group.d.ts.map +1 -0
- package/dist/tool-presentation.d.ts +20 -0
- package/dist/tool-presentation.d.ts.map +1 -0
- package/dist/types.d.ts +44 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/use-always-approve.d.ts +15 -0
- package/dist/use-always-approve.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ChatMessage, ChatMessageBubble, Markdown, ChatToolChip,
|
|
2
|
-
import {
|
|
3
|
-
import * as
|
|
1
|
+
import { ChatMessage, ChatMessageBubble, Markdown, Collapsible, CollapsibleTrigger, ChatToolChip, cn, CollapsiblePanel, ChatToolCard, ChatToolCardHeader, ChatToolCardActions, Button, Group, Spinner, Menu, MenuTrigger, MenuPopup, MenuItem, ChatHeader, ChatHeaderAvatar, ChatHeaderTitle, ChatHeaderActions, Tooltip, TooltipTrigger, TooltipContent, Chat, ChatMessages, ChatEmptyState, ChatEmptyStateIcon, ChatEmptyStateTitle, ChatEmptyStateDescription, ChatSuggestions, ChatSuggestion, ChatTypingIndicator, ChatInput, useMediaQuery, TooltipProvider, Fab, DataTablePaged } from '@cntyclub/ui-react';
|
|
2
|
+
import { ChevronDownIcon, CheckIcon, ShieldAlertIcon, CheckCheckIcon, HistoryIcon, SquarePenIcon, Minimize2Icon, Maximize2Icon, XIcon, Trash2Icon, SparklesIcon, CodeIcon } from 'lucide-react';
|
|
3
|
+
import * as React3 from 'react';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
|
|
6
6
|
// src/api-client.ts
|
|
@@ -77,6 +77,84 @@ var AgentApiClient = class {
|
|
|
77
77
|
});
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
|
+
|
|
81
|
+
// src/message-group.ts
|
|
82
|
+
function groupMessages(messages) {
|
|
83
|
+
const items = [];
|
|
84
|
+
let group = null;
|
|
85
|
+
let groupKey = "";
|
|
86
|
+
const stepIndexByCallId = /* @__PURE__ */ new Map();
|
|
87
|
+
const flush = () => {
|
|
88
|
+
if (group && group.length > 0) {
|
|
89
|
+
items.push({ key: `tools-${groupKey}`, kind: "tool-activity", steps: group });
|
|
90
|
+
}
|
|
91
|
+
group = null;
|
|
92
|
+
groupKey = "";
|
|
93
|
+
stepIndexByCallId.clear();
|
|
94
|
+
};
|
|
95
|
+
for (const message of messages) {
|
|
96
|
+
if (message.role === "user") {
|
|
97
|
+
flush();
|
|
98
|
+
items.push({ key: message.id, kind: "user", message });
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (message.role === "assistant") {
|
|
102
|
+
const hasText = Boolean(message.content && message.content.trim());
|
|
103
|
+
if (hasText) {
|
|
104
|
+
flush();
|
|
105
|
+
items.push({ key: message.id, kind: "assistant-text", message });
|
|
106
|
+
}
|
|
107
|
+
for (const toolCall of message.tool_calls ?? []) {
|
|
108
|
+
const callId2 = toolCall.id ?? `${message.id}-${toolCall.name}`;
|
|
109
|
+
if (!group) {
|
|
110
|
+
group = [];
|
|
111
|
+
groupKey = message.id;
|
|
112
|
+
}
|
|
113
|
+
stepIndexByCallId.set(callId2, group.length);
|
|
114
|
+
group.push({
|
|
115
|
+
args: toolCall.arguments ?? {},
|
|
116
|
+
callId: callId2,
|
|
117
|
+
name: toolCall.name ?? "tool",
|
|
118
|
+
status: "running"
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const callId = message.tool_call_id ?? "";
|
|
124
|
+
if (!group) {
|
|
125
|
+
group = [];
|
|
126
|
+
groupKey = message.id;
|
|
127
|
+
}
|
|
128
|
+
const existingIndex = callId ? stepIndexByCallId.get(callId) : void 0;
|
|
129
|
+
if (existingIndex !== void 0) {
|
|
130
|
+
const step = group[existingIndex];
|
|
131
|
+
step.status = "done";
|
|
132
|
+
step.result = message.result || step.result;
|
|
133
|
+
step.blocks = message.blocks ?? step.blocks;
|
|
134
|
+
} else {
|
|
135
|
+
group.push({
|
|
136
|
+
args: {},
|
|
137
|
+
blocks: message.blocks,
|
|
138
|
+
callId: callId || message.id,
|
|
139
|
+
name: message.tool_name ?? "tool",
|
|
140
|
+
result: message.result,
|
|
141
|
+
status: "done"
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
flush();
|
|
146
|
+
return items;
|
|
147
|
+
}
|
|
148
|
+
function MessageItem({ message }) {
|
|
149
|
+
if (message.role === "user") {
|
|
150
|
+
return /* @__PURE__ */ jsx(ChatMessage, { from: "user", children: /* @__PURE__ */ jsx(ChatMessageBubble, { from: "user", children: message.content }) });
|
|
151
|
+
}
|
|
152
|
+
if (message.role === "assistant") {
|
|
153
|
+
if (!message.content || !message.content.trim()) return null;
|
|
154
|
+
return /* @__PURE__ */ jsx(ChatMessage, { from: "assistant", children: /* @__PURE__ */ jsx(ChatMessageBubble, { from: "assistant", children: /* @__PURE__ */ jsx(Markdown, { children: message.content }) }) });
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
80
158
|
var NOISE_KEYS = /* @__PURE__ */ new Set([
|
|
81
159
|
"id",
|
|
82
160
|
"pk",
|
|
@@ -215,27 +293,72 @@ function toDisplayTable(block) {
|
|
|
215
293
|
});
|
|
216
294
|
return { columns, rows: displayRows };
|
|
217
295
|
}
|
|
296
|
+
|
|
297
|
+
// src/tool-presentation.ts
|
|
218
298
|
function humanizeToolName(toolName) {
|
|
219
299
|
return toolName.replace(/^[a-z]+_/, "").replaceAll("_", " ");
|
|
220
300
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
301
|
+
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
302
|
+
function isTechnicalKey(key) {
|
|
303
|
+
const lower = key.toLowerCase();
|
|
304
|
+
return lower === "id" || lower === "client_id" || lower === "slug" || lower.endsWith("_id") || lower.endsWith("_ids") || lower.endsWith("_key") || lower.endsWith("_slug") || lower.endsWith("_uuid") || lower === "uuid" || lower.endsWith("_s3_key") || lower === "embedding";
|
|
305
|
+
}
|
|
306
|
+
function isTechnicalValue(value) {
|
|
307
|
+
return typeof value === "string" && UUID_RE2.test(value.trim());
|
|
308
|
+
}
|
|
309
|
+
function humanizeKey(key) {
|
|
310
|
+
const spaced = key.replaceAll("_", " ").trim();
|
|
311
|
+
return spaced.charAt(0).toUpperCase() + spaced.slice(1);
|
|
312
|
+
}
|
|
313
|
+
function formatValue(value) {
|
|
314
|
+
if (value === null || value === void 0) return "\u2014";
|
|
315
|
+
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
316
|
+
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
317
|
+
if (Array.isArray(value)) {
|
|
318
|
+
const items = value.filter((item) => !isTechnicalValue(item)).map((item) => formatValue(item));
|
|
319
|
+
return items.length ? items.join(", ") : `${value.length} item${value.length === 1 ? "" : "s"}`;
|
|
224
320
|
}
|
|
225
|
-
if (
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
321
|
+
if (typeof value === "object") {
|
|
322
|
+
const record = value;
|
|
323
|
+
for (const key of ["name", "title", "label", "email"]) {
|
|
324
|
+
if (typeof record[key] === "string") return record[key];
|
|
325
|
+
}
|
|
326
|
+
return JSON.stringify(value);
|
|
327
|
+
}
|
|
328
|
+
return String(value);
|
|
329
|
+
}
|
|
330
|
+
function deriveDetails(args) {
|
|
331
|
+
const details = [];
|
|
332
|
+
for (const [key, value] of Object.entries(args ?? {})) {
|
|
333
|
+
if (isTechnicalKey(key)) continue;
|
|
334
|
+
if (isTechnicalValue(value)) continue;
|
|
335
|
+
if (value === "" || value === null || value === void 0) continue;
|
|
336
|
+
const formatted = formatValue(value);
|
|
337
|
+
if (!formatted || formatted === "\u2014") continue;
|
|
338
|
+
details.push({ label: humanizeKey(key), value: formatted.length > 140 ? `${formatted.slice(0, 140)}\u2026` : formatted });
|
|
236
339
|
}
|
|
237
|
-
|
|
238
|
-
|
|
340
|
+
return details;
|
|
341
|
+
}
|
|
342
|
+
function resolveToolPresentation(describe, toolName, args) {
|
|
343
|
+
let description;
|
|
344
|
+
try {
|
|
345
|
+
description = describe?.(toolName, args ?? {});
|
|
346
|
+
} catch {
|
|
347
|
+
description = null;
|
|
348
|
+
}
|
|
349
|
+
const title = description?.title?.trim() || humanizeToolName(toolName);
|
|
350
|
+
const summary = description?.summary?.trim() || null;
|
|
351
|
+
let details = description?.details ?? [];
|
|
352
|
+
const wantsDerived = description?.showDerivedDetails ?? description?.details === void 0;
|
|
353
|
+
if (details.length === 0 && wantsDerived) {
|
|
354
|
+
details = deriveDetails(args ?? {});
|
|
355
|
+
}
|
|
356
|
+
return { details, summary, title };
|
|
357
|
+
}
|
|
358
|
+
function StepTables({ blocks, stepKey }) {
|
|
359
|
+
const tables = (blocks ?? []).filter((block) => block.type === "table");
|
|
360
|
+
if (tables.length === 0) return null;
|
|
361
|
+
return /* @__PURE__ */ jsx(Fragment, { children: tables.map((block, index) => {
|
|
239
362
|
const { columns, rows } = toDisplayTable(block);
|
|
240
363
|
return /* @__PURE__ */ jsx("div", { className: "w-full max-w-full", children: /* @__PURE__ */ jsx(
|
|
241
364
|
DataTablePaged,
|
|
@@ -245,57 +368,127 @@ function MessageItem({ message }) {
|
|
|
245
368
|
rows,
|
|
246
369
|
totalCount: typeof block.pagination?.count === "number" ? block.pagination.count : block.row_count
|
|
247
370
|
}
|
|
248
|
-
) }, `${
|
|
249
|
-
})
|
|
250
|
-
humanizeToolName(message.tool_name ?? "tool"),
|
|
251
|
-
" finished"
|
|
252
|
-
] }) });
|
|
371
|
+
) }, `${stepKey}-table-${index}`);
|
|
372
|
+
}) });
|
|
253
373
|
}
|
|
254
|
-
function
|
|
255
|
-
return
|
|
374
|
+
function RawJsonDisclosure({ result }) {
|
|
375
|
+
return /* @__PURE__ */ jsxs(Collapsible, { className: "mt-1.5", children: [
|
|
376
|
+
/* @__PURE__ */ jsxs(CollapsibleTrigger, { className: "group flex items-center gap-1 text-muted-foreground text-xs hover:text-foreground", children: [
|
|
377
|
+
/* @__PURE__ */ jsx(CodeIcon, { className: "size-3" }),
|
|
378
|
+
/* @__PURE__ */ jsx("span", { children: "Raw JSON" }),
|
|
379
|
+
/* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-3 transition-transform group-data-[panel-open]:rotate-180" })
|
|
380
|
+
] }),
|
|
381
|
+
/* @__PURE__ */ jsx(CollapsiblePanel, { children: /* @__PURE__ */ jsx("pre", { className: "mt-1 max-h-64 overflow-auto rounded-lg bg-muted p-2 font-mono text-[11px] leading-snug text-muted-foreground", children: result }) })
|
|
382
|
+
] });
|
|
383
|
+
}
|
|
384
|
+
function StepDetail({
|
|
385
|
+
describeToolCall,
|
|
386
|
+
step
|
|
387
|
+
}) {
|
|
388
|
+
const { details, summary, title } = resolveToolPresentation(describeToolCall, step.name, step.args);
|
|
389
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-border/72 bg-card p-2.5", children: [
|
|
390
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 font-medium text-sm", children: [
|
|
391
|
+
step.status === "running" ? /* @__PURE__ */ jsx("span", { className: "size-1.5 animate-pulse rounded-full bg-warning" }) : /* @__PURE__ */ jsx(CheckIcon, { className: "size-3.5 text-success" }),
|
|
392
|
+
title
|
|
393
|
+
] }),
|
|
394
|
+
summary ? /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-muted-foreground text-xs", children: summary }) : null,
|
|
395
|
+
details.length > 0 ? /* @__PURE__ */ jsx("dl", { className: "mt-1.5 space-y-0.5 text-xs", children: details.map((detail) => /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
396
|
+
/* @__PURE__ */ jsx("dt", { className: "shrink-0 text-muted-foreground", children: detail.label }),
|
|
397
|
+
/* @__PURE__ */ jsx("dd", { className: "min-w-0 break-words", children: detail.value })
|
|
398
|
+
] }, detail.label)) }) : null,
|
|
399
|
+
step.result ? /* @__PURE__ */ jsx(RawJsonDisclosure, { result: step.result }) : null
|
|
400
|
+
] });
|
|
401
|
+
}
|
|
402
|
+
function ToolActivityGroup({ describeToolCall, steps }) {
|
|
403
|
+
const [open, setOpen] = React3.useState(false);
|
|
404
|
+
if (steps.length === 0) return null;
|
|
405
|
+
const last = steps[steps.length - 1];
|
|
406
|
+
const anyRunning = steps.some((step) => step.status === "running");
|
|
407
|
+
const lastTitle = resolveToolPresentation(describeToolCall, last.name, last.args).title || humanizeToolName(last.name);
|
|
408
|
+
const chipLabel = anyRunning ? `${lastTitle}\u2026` : steps.length > 1 ? lastTitle : `${lastTitle} finished`;
|
|
409
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-2", children: [
|
|
410
|
+
/* @__PURE__ */ jsxs(Collapsible, { onOpenChange: setOpen, open, children: [
|
|
411
|
+
/* @__PURE__ */ jsx(
|
|
412
|
+
CollapsibleTrigger,
|
|
413
|
+
{
|
|
414
|
+
render: /* @__PURE__ */ jsx(
|
|
415
|
+
ChatToolChip,
|
|
416
|
+
{
|
|
417
|
+
className: "cursor-pointer pr-2 hover:bg-muted",
|
|
418
|
+
icon: anyRunning ? /* @__PURE__ */ jsx("span", { className: "size-1.5 animate-pulse rounded-full bg-warning" }) : /* @__PURE__ */ jsx(CheckIcon, {}),
|
|
419
|
+
children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
420
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: chipLabel }),
|
|
421
|
+
steps.length > 1 ? /* @__PURE__ */ jsxs("span", { className: "rounded-full bg-background px-1.5 text-[10px] text-foreground/72", children: [
|
|
422
|
+
steps.length,
|
|
423
|
+
" steps"
|
|
424
|
+
] }) : null,
|
|
425
|
+
/* @__PURE__ */ jsx(ChevronDownIcon, { className: cn("size-3 transition-transform", open && "rotate-180") })
|
|
426
|
+
] })
|
|
427
|
+
}
|
|
428
|
+
)
|
|
429
|
+
}
|
|
430
|
+
),
|
|
431
|
+
/* @__PURE__ */ jsx(CollapsiblePanel, { children: /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-col gap-1.5", children: steps.map((step) => /* @__PURE__ */ jsx(StepDetail, { describeToolCall, step }, step.callId)) }) })
|
|
432
|
+
] }),
|
|
433
|
+
steps.map((step) => /* @__PURE__ */ jsx(StepTables, { blocks: step.blocks, stepKey: step.callId }, `${step.callId}-tables`))
|
|
434
|
+
] });
|
|
256
435
|
}
|
|
257
|
-
function ToolApprovalCard({
|
|
258
|
-
|
|
436
|
+
function ToolApprovalCard({
|
|
437
|
+
approval,
|
|
438
|
+
describeToolCall,
|
|
439
|
+
onAlwaysApprove,
|
|
440
|
+
onResolve,
|
|
441
|
+
resolving
|
|
442
|
+
}) {
|
|
443
|
+
const { details, summary, title } = resolveToolPresentation(
|
|
444
|
+
describeToolCall,
|
|
445
|
+
approval.tool_name,
|
|
446
|
+
approval.arguments ?? {}
|
|
447
|
+
);
|
|
259
448
|
return /* @__PURE__ */ jsxs(ChatToolCard, { className: "border-warning/40", children: [
|
|
260
449
|
/* @__PURE__ */ jsxs(ChatToolCardHeader, { children: [
|
|
261
450
|
/* @__PURE__ */ jsx(ShieldAlertIcon, { className: "size-4 text-warning" }),
|
|
262
451
|
"Approval needed"
|
|
263
452
|
] }),
|
|
264
|
-
/* @__PURE__ */
|
|
265
|
-
"The assistant wants to
|
|
266
|
-
" ",
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
/* @__PURE__ */ jsxs("dt", { className: "shrink-0 text-muted-foreground", children: [
|
|
274
|
-
key,
|
|
275
|
-
":"
|
|
276
|
-
] }),
|
|
277
|
-
/* @__PURE__ */ jsx("dd", { className: "truncate", children: typeof value === "object" ? JSON.stringify(value) : String(value) })
|
|
278
|
-
] }, key)),
|
|
279
|
-
argumentEntries.length > 8 && /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground", children: [
|
|
280
|
-
"\u2026and ",
|
|
281
|
-
argumentEntries.length - 8,
|
|
282
|
-
" more"
|
|
283
|
-
] })
|
|
284
|
-
] }),
|
|
453
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-muted-foreground", children: summary ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
454
|
+
"The assistant wants to ",
|
|
455
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: title.toLowerCase() }),
|
|
456
|
+
" \u2014 this will change your data."
|
|
457
|
+
] }) }),
|
|
458
|
+
details.length > 0 && /* @__PURE__ */ jsx("dl", { className: "mt-2 space-y-1 rounded-lg bg-muted p-2 text-xs", children: details.map((detail) => /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
459
|
+
/* @__PURE__ */ jsx("dt", { className: "shrink-0 text-muted-foreground", children: detail.label }),
|
|
460
|
+
/* @__PURE__ */ jsx("dd", { className: "min-w-0 break-words font-medium text-foreground", children: detail.value })
|
|
461
|
+
] }, detail.label)) }),
|
|
285
462
|
/* @__PURE__ */ jsxs(ChatToolCardActions, { children: [
|
|
286
|
-
/* @__PURE__ */ jsx(
|
|
287
|
-
|
|
288
|
-
{
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
463
|
+
/* @__PURE__ */ jsx(Button, { disabled: resolving, onClick: () => onResolve(approval.id, false), size: "sm", variant: "outline", children: "Decline" }),
|
|
464
|
+
/* @__PURE__ */ jsxs(Group, { children: [
|
|
465
|
+
/* @__PURE__ */ jsxs(Button, { disabled: resolving, onClick: () => onResolve(approval.id, true), size: "sm", children: [
|
|
466
|
+
resolving ? /* @__PURE__ */ jsx(Spinner, {}) : null,
|
|
467
|
+
"Approve"
|
|
468
|
+
] }),
|
|
469
|
+
/* @__PURE__ */ jsxs(Menu, { children: [
|
|
470
|
+
/* @__PURE__ */ jsx(
|
|
471
|
+
MenuTrigger,
|
|
472
|
+
{
|
|
473
|
+
render: /* @__PURE__ */ jsx(Button, { "aria-label": "More approve options", disabled: resolving, size: "icon-sm", variant: "default", children: /* @__PURE__ */ jsx(ChevronDownIcon, {}) })
|
|
474
|
+
}
|
|
475
|
+
),
|
|
476
|
+
/* @__PURE__ */ jsx(MenuPopup, { align: "end", children: /* @__PURE__ */ jsxs(
|
|
477
|
+
MenuItem,
|
|
478
|
+
{
|
|
479
|
+
onClick: () => {
|
|
480
|
+
onAlwaysApprove(approval.tool_name);
|
|
481
|
+
onResolve(approval.id, true);
|
|
482
|
+
},
|
|
483
|
+
children: [
|
|
484
|
+
/* @__PURE__ */ jsx(CheckCheckIcon, {}),
|
|
485
|
+
"Always approve \u201C",
|
|
486
|
+
title,
|
|
487
|
+
"\u201D"
|
|
488
|
+
]
|
|
489
|
+
}
|
|
490
|
+
) })
|
|
491
|
+
] })
|
|
299
492
|
] })
|
|
300
493
|
] })
|
|
301
494
|
] });
|
|
@@ -306,24 +499,25 @@ function AgentPanel({
|
|
|
306
499
|
chat,
|
|
307
500
|
className,
|
|
308
501
|
config,
|
|
502
|
+
onAlwaysApprove,
|
|
309
503
|
onClose,
|
|
310
504
|
onToggleAgentMode
|
|
311
505
|
}) {
|
|
312
|
-
const [draft, setDraft] =
|
|
313
|
-
const [view, setView] =
|
|
506
|
+
const [draft, setDraft] = React3.useState("");
|
|
507
|
+
const [view, setView] = React3.useState("chat");
|
|
314
508
|
const agentName = config.agentName ?? chat.agentInfo?.name ?? "Assistant";
|
|
315
509
|
const suggestions = config.suggestions ?? [
|
|
316
510
|
"What can you help me with?",
|
|
317
511
|
"Give me a quick summary of my data."
|
|
318
512
|
];
|
|
319
|
-
const handleSubmit =
|
|
513
|
+
const handleSubmit = React3.useCallback(
|
|
320
514
|
(text) => {
|
|
321
515
|
setDraft("");
|
|
322
516
|
void chat.send(text);
|
|
323
517
|
},
|
|
324
518
|
[chat]
|
|
325
519
|
);
|
|
326
|
-
const openHistory =
|
|
520
|
+
const openHistory = React3.useCallback(() => {
|
|
327
521
|
setView("history");
|
|
328
522
|
void chat.refreshConversations();
|
|
329
523
|
}, [chat]);
|
|
@@ -461,11 +655,15 @@ function AgentPanel({
|
|
|
461
655
|
suggestion
|
|
462
656
|
)) })
|
|
463
657
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
464
|
-
chat.messages.map(
|
|
658
|
+
groupMessages(chat.messages).map(
|
|
659
|
+
(item) => item.kind === "tool-activity" ? /* @__PURE__ */ jsx(ChatMessage, { from: "assistant", children: /* @__PURE__ */ jsx(ToolActivityGroup, { describeToolCall: config.describeToolCall, steps: item.steps }) }, item.key) : /* @__PURE__ */ jsx(MessageItem, { message: item.message }, item.key)
|
|
660
|
+
),
|
|
465
661
|
chat.pendingApprovals.map((approval) => /* @__PURE__ */ jsx(
|
|
466
662
|
ToolApprovalCard,
|
|
467
663
|
{
|
|
468
664
|
approval,
|
|
665
|
+
describeToolCall: config.describeToolCall,
|
|
666
|
+
onAlwaysApprove,
|
|
469
667
|
onResolve: (callId, approve) => void chat.resolveApproval(callId, approve),
|
|
470
668
|
resolving: chat.resolvingApprovalId === approval.id
|
|
471
669
|
},
|
|
@@ -494,16 +692,16 @@ function AgentPanel({
|
|
|
494
692
|
);
|
|
495
693
|
}
|
|
496
694
|
function useAgentChat(config) {
|
|
497
|
-
const client =
|
|
498
|
-
const [agentInfo, setAgentInfo] =
|
|
499
|
-
const [conversationId, setConversationId] =
|
|
500
|
-
const [conversations, setConversations] =
|
|
501
|
-
const [messages, setMessages] =
|
|
502
|
-
const [pendingApprovals, setPendingApprovals] =
|
|
503
|
-
const [sending, setSending] =
|
|
504
|
-
const [resolvingApprovalId, setResolvingApprovalId] =
|
|
505
|
-
const [error, setError] =
|
|
506
|
-
|
|
695
|
+
const client = React3.useMemo(() => new AgentApiClient(config), [config]);
|
|
696
|
+
const [agentInfo, setAgentInfo] = React3.useState(null);
|
|
697
|
+
const [conversationId, setConversationId] = React3.useState(null);
|
|
698
|
+
const [conversations, setConversations] = React3.useState([]);
|
|
699
|
+
const [messages, setMessages] = React3.useState([]);
|
|
700
|
+
const [pendingApprovals, setPendingApprovals] = React3.useState([]);
|
|
701
|
+
const [sending, setSending] = React3.useState(false);
|
|
702
|
+
const [resolvingApprovalId, setResolvingApprovalId] = React3.useState(null);
|
|
703
|
+
const [error, setError] = React3.useState(null);
|
|
704
|
+
React3.useEffect(() => {
|
|
507
705
|
let cancelled = false;
|
|
508
706
|
client.getConfig().then((info) => {
|
|
509
707
|
if (!cancelled) setAgentInfo(info);
|
|
@@ -513,11 +711,11 @@ function useAgentChat(config) {
|
|
|
513
711
|
cancelled = true;
|
|
514
712
|
};
|
|
515
713
|
}, [client]);
|
|
516
|
-
const handleFailure =
|
|
714
|
+
const handleFailure = React3.useCallback((err) => {
|
|
517
715
|
const message = err instanceof AgentApiError ? err.message : "Something went wrong. Please try again.";
|
|
518
716
|
setError(message);
|
|
519
717
|
}, []);
|
|
520
|
-
const applyResponse =
|
|
718
|
+
const applyResponse = React3.useCallback(
|
|
521
719
|
(response) => {
|
|
522
720
|
if (response.status === "error" && !response.messages?.length) {
|
|
523
721
|
setError(response.message ?? "The assistant could not answer.");
|
|
@@ -538,7 +736,7 @@ function useAgentChat(config) {
|
|
|
538
736
|
},
|
|
539
737
|
[]
|
|
540
738
|
);
|
|
541
|
-
const send =
|
|
739
|
+
const send = React3.useCallback(
|
|
542
740
|
async (text) => {
|
|
543
741
|
if (sending) return;
|
|
544
742
|
setSending(true);
|
|
@@ -554,7 +752,7 @@ function useAgentChat(config) {
|
|
|
554
752
|
},
|
|
555
753
|
[applyResponse, client, conversationId, handleFailure, sending]
|
|
556
754
|
);
|
|
557
|
-
const resolveApproval =
|
|
755
|
+
const resolveApproval = React3.useCallback(
|
|
558
756
|
async (callId, approve) => {
|
|
559
757
|
if (resolvingApprovalId) return;
|
|
560
758
|
setResolvingApprovalId(callId);
|
|
@@ -570,13 +768,13 @@ function useAgentChat(config) {
|
|
|
570
768
|
},
|
|
571
769
|
[applyResponse, client, handleFailure, resolvingApprovalId]
|
|
572
770
|
);
|
|
573
|
-
const newChat =
|
|
771
|
+
const newChat = React3.useCallback(() => {
|
|
574
772
|
setConversationId(null);
|
|
575
773
|
setMessages([]);
|
|
576
774
|
setPendingApprovals([]);
|
|
577
775
|
setError(null);
|
|
578
776
|
}, []);
|
|
579
|
-
const refreshConversations =
|
|
777
|
+
const refreshConversations = React3.useCallback(async () => {
|
|
580
778
|
try {
|
|
581
779
|
const { conversations: list } = await client.listConversations();
|
|
582
780
|
setConversations(list);
|
|
@@ -584,7 +782,7 @@ function useAgentChat(config) {
|
|
|
584
782
|
handleFailure(err);
|
|
585
783
|
}
|
|
586
784
|
}, [client, handleFailure]);
|
|
587
|
-
const openConversation =
|
|
785
|
+
const openConversation = React3.useCallback(
|
|
588
786
|
async (id) => {
|
|
589
787
|
setError(null);
|
|
590
788
|
try {
|
|
@@ -598,7 +796,7 @@ function useAgentChat(config) {
|
|
|
598
796
|
},
|
|
599
797
|
[client, handleFailure]
|
|
600
798
|
);
|
|
601
|
-
const deleteConversation =
|
|
799
|
+
const deleteConversation = React3.useCallback(
|
|
602
800
|
async (id) => {
|
|
603
801
|
try {
|
|
604
802
|
await client.deleteConversation(id);
|
|
@@ -610,7 +808,7 @@ function useAgentChat(config) {
|
|
|
610
808
|
},
|
|
611
809
|
[client, conversationId, handleFailure, newChat]
|
|
612
810
|
);
|
|
613
|
-
const clearError =
|
|
811
|
+
const clearError = React3.useCallback(() => setError(null), []);
|
|
614
812
|
return {
|
|
615
813
|
agentInfo,
|
|
616
814
|
clearError,
|
|
@@ -629,26 +827,86 @@ function useAgentChat(config) {
|
|
|
629
827
|
sending
|
|
630
828
|
};
|
|
631
829
|
}
|
|
830
|
+
var STORAGE_PREFIX = "cc-agent-always-approve:";
|
|
831
|
+
function storageKey(clientId) {
|
|
832
|
+
return `${STORAGE_PREFIX}${clientId || "default"}`;
|
|
833
|
+
}
|
|
834
|
+
function readStored(clientId) {
|
|
835
|
+
if (typeof window === "undefined") return /* @__PURE__ */ new Set();
|
|
836
|
+
try {
|
|
837
|
+
const raw = window.localStorage.getItem(storageKey(clientId));
|
|
838
|
+
if (!raw) return /* @__PURE__ */ new Set();
|
|
839
|
+
const parsed = JSON.parse(raw);
|
|
840
|
+
return Array.isArray(parsed) ? new Set(parsed.filter((v) => typeof v === "string")) : /* @__PURE__ */ new Set();
|
|
841
|
+
} catch {
|
|
842
|
+
return /* @__PURE__ */ new Set();
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
function useAlwaysApprove(clientId) {
|
|
846
|
+
const [approved, setApproved] = React3.useState(() => /* @__PURE__ */ new Set());
|
|
847
|
+
React3.useEffect(() => {
|
|
848
|
+
setApproved(readStored(clientId));
|
|
849
|
+
}, [clientId]);
|
|
850
|
+
const persist = React3.useCallback(
|
|
851
|
+
(next) => {
|
|
852
|
+
setApproved(next);
|
|
853
|
+
if (typeof window === "undefined") return;
|
|
854
|
+
try {
|
|
855
|
+
window.localStorage.setItem(storageKey(clientId), JSON.stringify([...next]));
|
|
856
|
+
} catch {
|
|
857
|
+
}
|
|
858
|
+
},
|
|
859
|
+
[clientId]
|
|
860
|
+
);
|
|
861
|
+
const isAlwaysApproved = React3.useCallback((toolName) => approved.has(toolName), [approved]);
|
|
862
|
+
const setAlwaysApprove = React3.useCallback(
|
|
863
|
+
(toolName) => {
|
|
864
|
+
if (approved.has(toolName)) return;
|
|
865
|
+
const next = new Set(approved);
|
|
866
|
+
next.add(toolName);
|
|
867
|
+
persist(next);
|
|
868
|
+
},
|
|
869
|
+
[approved, persist]
|
|
870
|
+
);
|
|
871
|
+
const clearAlwaysApprove = React3.useCallback(
|
|
872
|
+
(toolName) => {
|
|
873
|
+
if (!approved.has(toolName)) return;
|
|
874
|
+
const next = new Set(approved);
|
|
875
|
+
next.delete(toolName);
|
|
876
|
+
persist(next);
|
|
877
|
+
},
|
|
878
|
+
[approved, persist]
|
|
879
|
+
);
|
|
880
|
+
return { clearAlwaysApprove, isAlwaysApproved, setAlwaysApprove };
|
|
881
|
+
}
|
|
632
882
|
function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
633
|
-
const [uncontrolledOpen, setUncontrolledOpen] =
|
|
883
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React3.useState(false);
|
|
634
884
|
const open = controlledOpen ?? uncontrolledOpen;
|
|
635
|
-
const setOpen =
|
|
885
|
+
const setOpen = React3.useCallback(
|
|
636
886
|
(next) => {
|
|
637
887
|
setUncontrolledOpen(next);
|
|
638
888
|
onOpenChange?.(next);
|
|
639
889
|
},
|
|
640
890
|
[onOpenChange]
|
|
641
891
|
);
|
|
642
|
-
const [agentMode, setAgentMode] =
|
|
892
|
+
const [agentMode, setAgentMode] = React3.useState(false);
|
|
643
893
|
const isDesktop = useMediaQuery("(min-width: 640px)", {
|
|
644
894
|
defaultSSRValue: true,
|
|
645
895
|
ssr: true
|
|
646
896
|
});
|
|
647
897
|
const fullscreen = !isDesktop || agentMode;
|
|
648
898
|
const chat = useAgentChat(config);
|
|
649
|
-
const
|
|
899
|
+
const alwaysApprove = useAlwaysApprove(config.clientId);
|
|
900
|
+
const { pendingApprovals, resolveApproval, resolvingApprovalId } = chat;
|
|
901
|
+
const { isAlwaysApproved } = alwaysApprove;
|
|
902
|
+
React3.useEffect(() => {
|
|
903
|
+
if (!open || resolvingApprovalId) return;
|
|
904
|
+
const target = pendingApprovals.find((approval) => isAlwaysApproved(approval.tool_name));
|
|
905
|
+
if (target) void resolveApproval(target.id, true);
|
|
906
|
+
}, [open, pendingApprovals, resolvingApprovalId, isAlwaysApproved, resolveApproval]);
|
|
907
|
+
const lastNavigatedMessageId = React3.useRef(null);
|
|
650
908
|
const { messages } = chat;
|
|
651
|
-
|
|
909
|
+
React3.useEffect(() => {
|
|
652
910
|
if (!open || fullscreen || !config.navigate || !config.pages?.length) return;
|
|
653
911
|
const toolMessages = messages.filter((message) => message.role === "tool");
|
|
654
912
|
const latest = toolMessages[toolMessages.length - 1];
|
|
@@ -660,7 +918,7 @@ function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
|
660
918
|
const path = mapping.buildRoute ? mapping.buildRoute(args) : mapping.route;
|
|
661
919
|
if (path) config.navigate(path);
|
|
662
920
|
}, [config, fullscreen, messages, open]);
|
|
663
|
-
const closePanel =
|
|
921
|
+
const closePanel = React3.useCallback(() => {
|
|
664
922
|
setOpen(false);
|
|
665
923
|
setAgentMode(false);
|
|
666
924
|
}, [setOpen]);
|
|
@@ -688,6 +946,7 @@ function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
|
688
946
|
chat,
|
|
689
947
|
className: "flex-1",
|
|
690
948
|
config,
|
|
949
|
+
onAlwaysApprove: alwaysApprove.setAlwaysApprove,
|
|
691
950
|
onClose: closePanel,
|
|
692
951
|
onToggleAgentMode: () => setAgentMode((value) => !value)
|
|
693
952
|
}
|
|
@@ -713,6 +972,7 @@ function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
|
713
972
|
chat,
|
|
714
973
|
className: "flex-1",
|
|
715
974
|
config,
|
|
975
|
+
onAlwaysApprove: alwaysApprove.setAlwaysApprove,
|
|
716
976
|
onClose: closePanel,
|
|
717
977
|
onToggleAgentMode: () => setAgentMode(true)
|
|
718
978
|
}
|
|
@@ -737,6 +997,6 @@ function defineAgentConfig(config) {
|
|
|
737
997
|
return config;
|
|
738
998
|
}
|
|
739
999
|
|
|
740
|
-
export { AgentApiClient, AgentApiError, AgentPanel, AgentWidget, MessageItem, ToolApprovalCard, defineAgentConfig, useAgentChat };
|
|
1000
|
+
export { AgentApiClient, AgentApiError, AgentPanel, AgentWidget, MessageItem, ToolActivityGroup, ToolApprovalCard, defineAgentConfig, deriveDetails, groupMessages, humanizeToolName, resolveToolPresentation, useAgentChat, useAlwaysApprove };
|
|
741
1001
|
//# sourceMappingURL=index.js.map
|
|
742
1002
|
//# sourceMappingURL=index.js.map
|