@cntyclub/agent-react 0.3.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 +496 -95
- 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/table-format.d.ts +29 -0
- package/dist/table-format.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,84 +77,418 @@ var AgentApiClient = class {
|
|
|
77
77
|
});
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
|
-
|
|
81
|
-
|
|
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;
|
|
82
147
|
}
|
|
83
148
|
function MessageItem({ message }) {
|
|
84
149
|
if (message.role === "user") {
|
|
85
150
|
return /* @__PURE__ */ jsx(ChatMessage, { from: "user", children: /* @__PURE__ */ jsx(ChatMessageBubble, { from: "user", children: message.content }) });
|
|
86
151
|
}
|
|
87
152
|
if (message.role === "assistant") {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return /* @__PURE__ */ jsxs(ChatMessage, { from: "assistant", children: [
|
|
91
|
-
message.content ? /* @__PURE__ */ jsx(ChatMessageBubble, { from: "assistant", children: /* @__PURE__ */ jsx(Markdown, { children: message.content }) }) : null,
|
|
92
|
-
requestedTools.map((toolCall) => /* @__PURE__ */ jsxs(ChatToolChip, { icon: /* @__PURE__ */ jsx(WrenchIcon, {}), children: [
|
|
93
|
-
"Using ",
|
|
94
|
-
humanizeToolName(toolCall.name ?? "tool"),
|
|
95
|
-
"\u2026"
|
|
96
|
-
] }, toolCall.id ?? toolCall.name))
|
|
97
|
-
] });
|
|
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 }) }) });
|
|
98
155
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
var NOISE_KEYS = /* @__PURE__ */ new Set([
|
|
159
|
+
"id",
|
|
160
|
+
"pk",
|
|
161
|
+
"uuid",
|
|
162
|
+
"slug",
|
|
163
|
+
"object_id",
|
|
164
|
+
"external_id",
|
|
165
|
+
"client_id",
|
|
166
|
+
"content_type",
|
|
167
|
+
"provider_call_id",
|
|
168
|
+
"tool_call_id"
|
|
169
|
+
]);
|
|
170
|
+
var NOISE_PATTERNS = [
|
|
171
|
+
/_id$/i,
|
|
172
|
+
/_ids$/i,
|
|
173
|
+
/_key$/i,
|
|
174
|
+
/_hash$/i,
|
|
175
|
+
/embedding/i,
|
|
176
|
+
/vector/i,
|
|
177
|
+
/password/i,
|
|
178
|
+
/secret/i,
|
|
179
|
+
/(^|_)token(_|$)/i
|
|
180
|
+
];
|
|
181
|
+
var IMAGE_KEY = /(image|logo|avatar|photo|picture|icon|thumbnail|banner|cover|headshot)/i;
|
|
182
|
+
var IMAGE_EXT = /\.(png|jpe?g|gif|webp|svg|avif)(\?|$)/i;
|
|
183
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
184
|
+
var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}(T|$)/;
|
|
185
|
+
var URL_RE = /^https?:\/\//i;
|
|
186
|
+
var PRIORITY_KEYS = ["name", "title", "label", "full_name", "email"];
|
|
187
|
+
var LABEL_KEYS = ["name", "title", "label", "full_name", "email", "code"];
|
|
188
|
+
function isUuid(value) {
|
|
189
|
+
return typeof value === "string" && UUID_RE.test(value);
|
|
190
|
+
}
|
|
191
|
+
function humanize(key) {
|
|
192
|
+
const text = key.replace(/_/g, " ").trim();
|
|
193
|
+
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
194
|
+
}
|
|
195
|
+
function isNoiseColumn(key, rows) {
|
|
196
|
+
if (NOISE_KEYS.has(key.toLowerCase())) return true;
|
|
197
|
+
if (NOISE_PATTERNS.some((pattern) => pattern.test(key))) return true;
|
|
198
|
+
const values = rows.map((row) => row[key]).filter((value) => value !== null && value !== void 0 && value !== "");
|
|
199
|
+
return values.length > 0 && values.every(isUuid);
|
|
200
|
+
}
|
|
201
|
+
function pickLabel(obj) {
|
|
202
|
+
for (const key of LABEL_KEYS) {
|
|
203
|
+
const value = obj[key];
|
|
204
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
205
|
+
if (typeof value === "number") return String(value);
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
function formatObject(obj) {
|
|
210
|
+
const label = pickLabel(obj);
|
|
211
|
+
if (label) return label;
|
|
212
|
+
const parts = [];
|
|
213
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
214
|
+
if (value === null || value === void 0 || value === "") continue;
|
|
215
|
+
if (typeof value === "object") continue;
|
|
216
|
+
parts.push(`${humanize(key)} ${value}`);
|
|
217
|
+
if (parts.length >= 6) break;
|
|
218
|
+
}
|
|
219
|
+
return parts.join(" \xB7 ") || "\u2014";
|
|
220
|
+
}
|
|
221
|
+
function formatArray(arr) {
|
|
222
|
+
const items = arr.map((item) => {
|
|
223
|
+
if (item === null || item === void 0) return "";
|
|
224
|
+
if (Array.isArray(item)) return "";
|
|
225
|
+
if (typeof item === "object") return pickLabel(item) ?? "";
|
|
226
|
+
return String(item);
|
|
227
|
+
}).filter(Boolean);
|
|
228
|
+
if (items.length === 0) return "\u2014";
|
|
229
|
+
const shown = items.slice(0, 8);
|
|
230
|
+
const extra = items.length - shown.length;
|
|
231
|
+
return shown.join(", ") + (extra > 0 ? ` +${extra} more` : "");
|
|
232
|
+
}
|
|
233
|
+
function renderScalar(key, value) {
|
|
234
|
+
if (typeof value !== "string") return value;
|
|
235
|
+
const text = value.trim();
|
|
236
|
+
if (URL_RE.test(text) && (IMAGE_EXT.test(text) || IMAGE_KEY.test(key))) {
|
|
237
|
+
return /* @__PURE__ */ jsx(
|
|
238
|
+
"img",
|
|
239
|
+
{
|
|
240
|
+
alt: humanize(key),
|
|
241
|
+
className: "h-9 w-9 rounded-md border border-border object-cover",
|
|
242
|
+
loading: "lazy",
|
|
243
|
+
src: text
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
if (URL_RE.test(text)) {
|
|
248
|
+
let label = text;
|
|
249
|
+
try {
|
|
250
|
+
label = new URL(text).hostname.replace(/^www\./, "");
|
|
251
|
+
} catch {
|
|
107
252
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
253
|
+
return /* @__PURE__ */ jsx(
|
|
254
|
+
"a",
|
|
255
|
+
{
|
|
256
|
+
className: "text-primary underline underline-offset-2",
|
|
257
|
+
href: text,
|
|
258
|
+
rel: "noreferrer",
|
|
259
|
+
target: "_blank",
|
|
260
|
+
children: label
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
if (ISO_DATE_RE.test(text)) {
|
|
265
|
+
const date = new Date(text);
|
|
266
|
+
if (!Number.isNaN(date.getTime())) return date.toLocaleDateString();
|
|
267
|
+
}
|
|
268
|
+
return text;
|
|
112
269
|
}
|
|
113
|
-
function
|
|
270
|
+
function formatCellValue(key, value) {
|
|
271
|
+
if (value === null || value === void 0 || value === "") return value;
|
|
272
|
+
if (Array.isArray(value)) return formatArray(value);
|
|
273
|
+
if (typeof value === "object") return formatObject(value);
|
|
274
|
+
return renderScalar(key, value);
|
|
275
|
+
}
|
|
276
|
+
function toDisplayTable(block) {
|
|
277
|
+
const rows = block.rows ?? [];
|
|
278
|
+
const kept = (block.columns ?? []).filter((key) => !isNoiseColumn(key, rows));
|
|
279
|
+
const columnKeys = kept.length > 0 ? kept : block.columns ?? [];
|
|
280
|
+
const ordered = [...columnKeys].sort((a, b) => {
|
|
281
|
+
const ra = PRIORITY_KEYS.indexOf(a.toLowerCase());
|
|
282
|
+
const rb = PRIORITY_KEYS.indexOf(b.toLowerCase());
|
|
283
|
+
const pa = ra === -1 ? PRIORITY_KEYS.length : ra;
|
|
284
|
+
const pb = rb === -1 ? PRIORITY_KEYS.length : rb;
|
|
285
|
+
if (pa !== pb) return pa - pb;
|
|
286
|
+
return columnKeys.indexOf(a) - columnKeys.indexOf(b);
|
|
287
|
+
});
|
|
288
|
+
const columns = ordered.map((key) => ({ key, label: humanize(key) }));
|
|
289
|
+
const displayRows = rows.map((row) => {
|
|
290
|
+
const out = {};
|
|
291
|
+
for (const key of ordered) out[key] = formatCellValue(key, row[key]);
|
|
292
|
+
return out;
|
|
293
|
+
});
|
|
294
|
+
return { columns, rows: displayRows };
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// src/tool-presentation.ts
|
|
298
|
+
function humanizeToolName(toolName) {
|
|
114
299
|
return toolName.replace(/^[a-z]+_/, "").replaceAll("_", " ");
|
|
115
300
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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"}`;
|
|
320
|
+
}
|
|
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 });
|
|
339
|
+
}
|
|
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) => {
|
|
362
|
+
const { columns, rows } = toDisplayTable(block);
|
|
363
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full max-w-full", children: /* @__PURE__ */ jsx(
|
|
364
|
+
DataTablePaged,
|
|
365
|
+
{
|
|
366
|
+
columns,
|
|
367
|
+
pageSize: 8,
|
|
368
|
+
rows,
|
|
369
|
+
totalCount: typeof block.pagination?.count === "number" ? block.pagination.count : block.row_count
|
|
370
|
+
}
|
|
371
|
+
) }, `${stepKey}-table-${index}`);
|
|
372
|
+
}) });
|
|
373
|
+
}
|
|
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" })
|
|
129
380
|
] }),
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
] })
|
|
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
|
|
143
393
|
] }),
|
|
144
|
-
/* @__PURE__ */
|
|
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: [
|
|
145
411
|
/* @__PURE__ */ jsx(
|
|
146
|
-
|
|
412
|
+
CollapsibleTrigger,
|
|
147
413
|
{
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
+
)
|
|
153
429
|
}
|
|
154
430
|
),
|
|
155
|
-
/* @__PURE__ */
|
|
156
|
-
|
|
157
|
-
|
|
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
|
+
] });
|
|
435
|
+
}
|
|
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
|
+
);
|
|
448
|
+
return /* @__PURE__ */ jsxs(ChatToolCard, { className: "border-warning/40", children: [
|
|
449
|
+
/* @__PURE__ */ jsxs(ChatToolCardHeader, { children: [
|
|
450
|
+
/* @__PURE__ */ jsx(ShieldAlertIcon, { className: "size-4 text-warning" }),
|
|
451
|
+
"Approval needed"
|
|
452
|
+
] }),
|
|
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)) }),
|
|
462
|
+
/* @__PURE__ */ jsxs(ChatToolCardActions, { children: [
|
|
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
|
+
] })
|
|
158
492
|
] })
|
|
159
493
|
] })
|
|
160
494
|
] });
|
|
@@ -165,24 +499,25 @@ function AgentPanel({
|
|
|
165
499
|
chat,
|
|
166
500
|
className,
|
|
167
501
|
config,
|
|
502
|
+
onAlwaysApprove,
|
|
168
503
|
onClose,
|
|
169
504
|
onToggleAgentMode
|
|
170
505
|
}) {
|
|
171
|
-
const [draft, setDraft] =
|
|
172
|
-
const [view, setView] =
|
|
506
|
+
const [draft, setDraft] = React3.useState("");
|
|
507
|
+
const [view, setView] = React3.useState("chat");
|
|
173
508
|
const agentName = config.agentName ?? chat.agentInfo?.name ?? "Assistant";
|
|
174
509
|
const suggestions = config.suggestions ?? [
|
|
175
510
|
"What can you help me with?",
|
|
176
511
|
"Give me a quick summary of my data."
|
|
177
512
|
];
|
|
178
|
-
const handleSubmit =
|
|
513
|
+
const handleSubmit = React3.useCallback(
|
|
179
514
|
(text) => {
|
|
180
515
|
setDraft("");
|
|
181
516
|
void chat.send(text);
|
|
182
517
|
},
|
|
183
518
|
[chat]
|
|
184
519
|
);
|
|
185
|
-
const openHistory =
|
|
520
|
+
const openHistory = React3.useCallback(() => {
|
|
186
521
|
setView("history");
|
|
187
522
|
void chat.refreshConversations();
|
|
188
523
|
}, [chat]);
|
|
@@ -320,11 +655,15 @@ function AgentPanel({
|
|
|
320
655
|
suggestion
|
|
321
656
|
)) })
|
|
322
657
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
323
|
-
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
|
+
),
|
|
324
661
|
chat.pendingApprovals.map((approval) => /* @__PURE__ */ jsx(
|
|
325
662
|
ToolApprovalCard,
|
|
326
663
|
{
|
|
327
664
|
approval,
|
|
665
|
+
describeToolCall: config.describeToolCall,
|
|
666
|
+
onAlwaysApprove,
|
|
328
667
|
onResolve: (callId, approve) => void chat.resolveApproval(callId, approve),
|
|
329
668
|
resolving: chat.resolvingApprovalId === approval.id
|
|
330
669
|
},
|
|
@@ -353,16 +692,16 @@ function AgentPanel({
|
|
|
353
692
|
);
|
|
354
693
|
}
|
|
355
694
|
function useAgentChat(config) {
|
|
356
|
-
const client =
|
|
357
|
-
const [agentInfo, setAgentInfo] =
|
|
358
|
-
const [conversationId, setConversationId] =
|
|
359
|
-
const [conversations, setConversations] =
|
|
360
|
-
const [messages, setMessages] =
|
|
361
|
-
const [pendingApprovals, setPendingApprovals] =
|
|
362
|
-
const [sending, setSending] =
|
|
363
|
-
const [resolvingApprovalId, setResolvingApprovalId] =
|
|
364
|
-
const [error, setError] =
|
|
365
|
-
|
|
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(() => {
|
|
366
705
|
let cancelled = false;
|
|
367
706
|
client.getConfig().then((info) => {
|
|
368
707
|
if (!cancelled) setAgentInfo(info);
|
|
@@ -372,11 +711,11 @@ function useAgentChat(config) {
|
|
|
372
711
|
cancelled = true;
|
|
373
712
|
};
|
|
374
713
|
}, [client]);
|
|
375
|
-
const handleFailure =
|
|
714
|
+
const handleFailure = React3.useCallback((err) => {
|
|
376
715
|
const message = err instanceof AgentApiError ? err.message : "Something went wrong. Please try again.";
|
|
377
716
|
setError(message);
|
|
378
717
|
}, []);
|
|
379
|
-
const applyResponse =
|
|
718
|
+
const applyResponse = React3.useCallback(
|
|
380
719
|
(response) => {
|
|
381
720
|
if (response.status === "error" && !response.messages?.length) {
|
|
382
721
|
setError(response.message ?? "The assistant could not answer.");
|
|
@@ -397,7 +736,7 @@ function useAgentChat(config) {
|
|
|
397
736
|
},
|
|
398
737
|
[]
|
|
399
738
|
);
|
|
400
|
-
const send =
|
|
739
|
+
const send = React3.useCallback(
|
|
401
740
|
async (text) => {
|
|
402
741
|
if (sending) return;
|
|
403
742
|
setSending(true);
|
|
@@ -413,7 +752,7 @@ function useAgentChat(config) {
|
|
|
413
752
|
},
|
|
414
753
|
[applyResponse, client, conversationId, handleFailure, sending]
|
|
415
754
|
);
|
|
416
|
-
const resolveApproval =
|
|
755
|
+
const resolveApproval = React3.useCallback(
|
|
417
756
|
async (callId, approve) => {
|
|
418
757
|
if (resolvingApprovalId) return;
|
|
419
758
|
setResolvingApprovalId(callId);
|
|
@@ -429,13 +768,13 @@ function useAgentChat(config) {
|
|
|
429
768
|
},
|
|
430
769
|
[applyResponse, client, handleFailure, resolvingApprovalId]
|
|
431
770
|
);
|
|
432
|
-
const newChat =
|
|
771
|
+
const newChat = React3.useCallback(() => {
|
|
433
772
|
setConversationId(null);
|
|
434
773
|
setMessages([]);
|
|
435
774
|
setPendingApprovals([]);
|
|
436
775
|
setError(null);
|
|
437
776
|
}, []);
|
|
438
|
-
const refreshConversations =
|
|
777
|
+
const refreshConversations = React3.useCallback(async () => {
|
|
439
778
|
try {
|
|
440
779
|
const { conversations: list } = await client.listConversations();
|
|
441
780
|
setConversations(list);
|
|
@@ -443,7 +782,7 @@ function useAgentChat(config) {
|
|
|
443
782
|
handleFailure(err);
|
|
444
783
|
}
|
|
445
784
|
}, [client, handleFailure]);
|
|
446
|
-
const openConversation =
|
|
785
|
+
const openConversation = React3.useCallback(
|
|
447
786
|
async (id) => {
|
|
448
787
|
setError(null);
|
|
449
788
|
try {
|
|
@@ -457,7 +796,7 @@ function useAgentChat(config) {
|
|
|
457
796
|
},
|
|
458
797
|
[client, handleFailure]
|
|
459
798
|
);
|
|
460
|
-
const deleteConversation =
|
|
799
|
+
const deleteConversation = React3.useCallback(
|
|
461
800
|
async (id) => {
|
|
462
801
|
try {
|
|
463
802
|
await client.deleteConversation(id);
|
|
@@ -469,7 +808,7 @@ function useAgentChat(config) {
|
|
|
469
808
|
},
|
|
470
809
|
[client, conversationId, handleFailure, newChat]
|
|
471
810
|
);
|
|
472
|
-
const clearError =
|
|
811
|
+
const clearError = React3.useCallback(() => setError(null), []);
|
|
473
812
|
return {
|
|
474
813
|
agentInfo,
|
|
475
814
|
clearError,
|
|
@@ -488,26 +827,86 @@ function useAgentChat(config) {
|
|
|
488
827
|
sending
|
|
489
828
|
};
|
|
490
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
|
+
}
|
|
491
882
|
function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
492
|
-
const [uncontrolledOpen, setUncontrolledOpen] =
|
|
883
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React3.useState(false);
|
|
493
884
|
const open = controlledOpen ?? uncontrolledOpen;
|
|
494
|
-
const setOpen =
|
|
885
|
+
const setOpen = React3.useCallback(
|
|
495
886
|
(next) => {
|
|
496
887
|
setUncontrolledOpen(next);
|
|
497
888
|
onOpenChange?.(next);
|
|
498
889
|
},
|
|
499
890
|
[onOpenChange]
|
|
500
891
|
);
|
|
501
|
-
const [agentMode, setAgentMode] =
|
|
892
|
+
const [agentMode, setAgentMode] = React3.useState(false);
|
|
502
893
|
const isDesktop = useMediaQuery("(min-width: 640px)", {
|
|
503
894
|
defaultSSRValue: true,
|
|
504
895
|
ssr: true
|
|
505
896
|
});
|
|
506
897
|
const fullscreen = !isDesktop || agentMode;
|
|
507
898
|
const chat = useAgentChat(config);
|
|
508
|
-
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);
|
|
509
908
|
const { messages } = chat;
|
|
510
|
-
|
|
909
|
+
React3.useEffect(() => {
|
|
511
910
|
if (!open || fullscreen || !config.navigate || !config.pages?.length) return;
|
|
512
911
|
const toolMessages = messages.filter((message) => message.role === "tool");
|
|
513
912
|
const latest = toolMessages[toolMessages.length - 1];
|
|
@@ -519,7 +918,7 @@ function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
|
519
918
|
const path = mapping.buildRoute ? mapping.buildRoute(args) : mapping.route;
|
|
520
919
|
if (path) config.navigate(path);
|
|
521
920
|
}, [config, fullscreen, messages, open]);
|
|
522
|
-
const closePanel =
|
|
921
|
+
const closePanel = React3.useCallback(() => {
|
|
523
922
|
setOpen(false);
|
|
524
923
|
setAgentMode(false);
|
|
525
924
|
}, [setOpen]);
|
|
@@ -547,6 +946,7 @@ function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
|
547
946
|
chat,
|
|
548
947
|
className: "flex-1",
|
|
549
948
|
config,
|
|
949
|
+
onAlwaysApprove: alwaysApprove.setAlwaysApprove,
|
|
550
950
|
onClose: closePanel,
|
|
551
951
|
onToggleAgentMode: () => setAgentMode((value) => !value)
|
|
552
952
|
}
|
|
@@ -572,6 +972,7 @@ function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
|
572
972
|
chat,
|
|
573
973
|
className: "flex-1",
|
|
574
974
|
config,
|
|
975
|
+
onAlwaysApprove: alwaysApprove.setAlwaysApprove,
|
|
575
976
|
onClose: closePanel,
|
|
576
977
|
onToggleAgentMode: () => setAgentMode(true)
|
|
577
978
|
}
|
|
@@ -596,6 +997,6 @@ function defineAgentConfig(config) {
|
|
|
596
997
|
return config;
|
|
597
998
|
}
|
|
598
999
|
|
|
599
|
-
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 };
|
|
600
1001
|
//# sourceMappingURL=index.js.map
|
|
601
1002
|
//# sourceMappingURL=index.js.map
|