@sarchauhan/chat 0.0.0-stage → 0.0.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.
@@ -0,0 +1,1996 @@
1
+ "use client";
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/widgets/index.ts
32
+ var widgets_exports = {};
33
+ __export(widgets_exports, {
34
+ ArtifactWidget: () => ArtifactWidget,
35
+ ArtifactsWidget: () => ArtifactsWidget,
36
+ PatchWidget: () => PatchWidget,
37
+ QuestionWidget: () => QuestionWidget,
38
+ ReadFileWidget: () => ReadFileWidget,
39
+ ResponsiveDetail: () => ResponsiveDetail,
40
+ SearchWidget: () => SearchWidget,
41
+ SubagentWidget: () => SubagentWidget,
42
+ computeDiff: () => computeDiff,
43
+ computeTextDiff: () => computeTextDiff,
44
+ computeToolState: () => computeToolState,
45
+ computeToolWidget: () => computeToolWidget,
46
+ createArtifactData: () => import_protocol4.createArtifactData,
47
+ createSubagentData: () => import_protocol4.createSubagentData,
48
+ formatArtifactSize: () => formatArtifactSize,
49
+ normalizeSearchResults: () => normalizeSearchResults,
50
+ parseArtifact: () => import_protocol4.parseArtifact,
51
+ parseSubagent: () => import_protocol4.parseSubagent,
52
+ prebuiltWidgets: () => prebuiltWidgets,
53
+ safeArtifactUrl: () => safeArtifactUrl,
54
+ safeResultUrl: () => safeResultUrl
55
+ });
56
+ module.exports = __toCommonJS(widgets_exports);
57
+
58
+ // src/widgets/read-file.tsx
59
+ var import_react = require("react");
60
+
61
+ // src/widgets/tool-frame.tsx
62
+ var import_lucide_react = require("lucide-react");
63
+ var import_jsx_runtime = require("react/jsx-runtime");
64
+ function ToolFrame({
65
+ label,
66
+ title,
67
+ meta,
68
+ state = "complete",
69
+ error,
70
+ className = "",
71
+ children
72
+ }) {
73
+ const status = {
74
+ running: "Working",
75
+ complete: "Done",
76
+ error: "Failed",
77
+ denied: "Denied",
78
+ approval: "Needs approval"
79
+ }[state];
80
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
81
+ "details",
82
+ {
83
+ className: `chat-prebuilt chat-tool-widget ${className}`,
84
+ "data-state": state,
85
+ open: state !== "complete",
86
+ children: [
87
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("summary", { children: [
88
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronDown, { size: 14, "aria-hidden": "true" }),
89
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chat-tool-widget-label", children: label }),
90
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chat-tool-widget-title", title, children: title }),
91
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chat-tool-widget-meta", children: meta }),
92
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chat-tool-widget-status", role: "status", children: status })
93
+ ] }),
94
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "chat-tool-widget-body", children: error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "chat-widget-error", role: "alert", children: error }) : children })
95
+ ]
96
+ }
97
+ );
98
+ }
99
+
100
+ // src/widgets/read-file.tsx
101
+ var import_jsx_runtime2 = require("react/jsx-runtime");
102
+ function ReadFileWidget({
103
+ path,
104
+ content,
105
+ startLine = 1,
106
+ language,
107
+ maxLines = 80,
108
+ ...props
109
+ }) {
110
+ var _a;
111
+ const [expanded, setExpanded] = (0, import_react.useState)(false);
112
+ const lines = (_a = content == null ? void 0 : content.split(/\r?\n/)) != null ? _a : [];
113
+ const limit = Math.max(1, maxLines);
114
+ const firstLine = Math.max(1, Math.floor(startLine));
115
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
116
+ ToolFrame,
117
+ {
118
+ ...props,
119
+ label: "Read file",
120
+ title: path,
121
+ meta: lines.length ? `${lines.length} lines` : language,
122
+ children: [
123
+ content === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "chat-widget-empty", children: props.state === "running" ? "Reading file\u2026" : "No file content supplied." }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
124
+ "div",
125
+ {
126
+ className: "chat-code-preview",
127
+ role: "region",
128
+ "aria-label": `Contents of ${path}`,
129
+ tabIndex: 0,
130
+ children: (expanded ? lines : lines.slice(0, limit)).map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "chat-code-line", children: [
131
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "chat-line-number", "aria-hidden": "true", children: firstLine + index }),
132
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: line || " " })
133
+ ] }, index))
134
+ }
135
+ ),
136
+ !expanded && lines.length > limit ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
137
+ "button",
138
+ {
139
+ className: "chat-widget-more",
140
+ type: "button",
141
+ onClick: () => setExpanded(true),
142
+ children: [
143
+ "Show ",
144
+ lines.length - limit,
145
+ " more lines"
146
+ ]
147
+ }
148
+ ) : null
149
+ ]
150
+ }
151
+ );
152
+ }
153
+
154
+ // src/widgets/patch.tsx
155
+ var import_react2 = require("react");
156
+
157
+ // src/widgets/compute.ts
158
+ var import_protocol = require("@sarchauhan/protocol");
159
+ var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
160
+ var string = (...values) => values.find((value) => typeof value === "string");
161
+ var number = (...values) => values.find(
162
+ (value) => typeof value === "number" && Number.isFinite(value)
163
+ );
164
+ var aliases = {
165
+ read: "read-file",
166
+ read_file: "read-file",
167
+ readFile: "read-file",
168
+ "read-file": "read-file",
169
+ patch: "patch",
170
+ apply_patch: "patch",
171
+ edit_file: "patch",
172
+ edit: "patch",
173
+ search: "search",
174
+ grep: "search",
175
+ file_search: "search",
176
+ web_search: "search",
177
+ question: "question",
178
+ ask_question: "question"
179
+ };
180
+ function computeToolState(part) {
181
+ if (part.state === "output-error") return "error";
182
+ if (part.state === "output-denied") return "denied";
183
+ if (part.state === "approval-requested") return "approval";
184
+ return part.state === "output-available" && !part.preliminary ? "complete" : "running";
185
+ }
186
+ function normalizeSearchResults(value) {
187
+ if (!Array.isArray(value)) return [];
188
+ return value.flatMap((item) => {
189
+ const result = record(item);
190
+ const path = string(result.path, result.file, result.url);
191
+ if (!path) return [];
192
+ return [
193
+ {
194
+ path,
195
+ line: number(result.line, result.lineNumber),
196
+ text: string(result.text, result.snippet, result.content),
197
+ title: string(result.title),
198
+ url: string(result.url)
199
+ }
200
+ ];
201
+ });
202
+ }
203
+ function computeToolWidget(part) {
204
+ var _a, _b, _c;
205
+ const name = aliases[part.toolName];
206
+ if (!name) {
207
+ const output2 = record(part.output);
208
+ if (part.state !== "output-available") return null;
209
+ if (Array.isArray(output2.artifacts)) {
210
+ const artifacts = output2.artifacts.flatMap((value) => {
211
+ const artifact2 = (0, import_protocol.parseArtifact)(value);
212
+ return artifact2 ? [artifact2] : [];
213
+ });
214
+ return artifacts.length ? { type: "widget", name: "artifacts", id: part.toolCallId, props: { artifacts } } : null;
215
+ }
216
+ const artifact = (0, import_protocol.parseArtifact)(output2.artifact);
217
+ return artifact ? { type: "widget", name: "artifact", id: part.toolCallId, props: { artifact } } : null;
218
+ }
219
+ const input = record(part.input), output = record(part.output);
220
+ const values = { ...input, ...output };
221
+ const common2 = { state: computeToolState(part), error: part.errorText };
222
+ let props;
223
+ if (name === "read-file") {
224
+ const path = string(
225
+ values.path,
226
+ values.file,
227
+ values.filename,
228
+ values.file_path
229
+ );
230
+ if (!path) return null;
231
+ props = {
232
+ ...common2,
233
+ path,
234
+ content: string(output.content, output.text, part.output),
235
+ startLine: number(values.startLine, values.start_line, values.offset),
236
+ language: string(values.language)
237
+ };
238
+ if (part.state === "output-available" && props.content === void 0)
239
+ return null;
240
+ } else if (name === "patch") {
241
+ const before = string(values.before, values.old_string, values.oldText);
242
+ const after = string(values.after, values.new_string, values.newText);
243
+ const diff = (_a = string(
244
+ output.diff,
245
+ output.patch,
246
+ input.diff,
247
+ input.patch,
248
+ part.input,
249
+ part.output
250
+ )) != null ? _a : before !== void 0 && after !== void 0 ? computeTextDiff(
251
+ before,
252
+ after,
253
+ string(values.path, values.file_path, "file")
254
+ ) : void 0;
255
+ if (diff === void 0 || diff && !/^(@@|diff --git|--- |\*\*\* Begin Patch)/m.test(diff))
256
+ return null;
257
+ props = {
258
+ ...common2,
259
+ path: string(values.path, values.file, values.file_path),
260
+ diff
261
+ };
262
+ } else if (name === "search") {
263
+ const query = string(values.query, values.pattern, values.search);
264
+ if (query === void 0) return null;
265
+ const results = (_c = (_b = output.results) != null ? _b : output.matches) != null ? _c : Array.isArray(part.output) ? part.output : void 0;
266
+ if (part.state === "output-available" && !Array.isArray(results))
267
+ return null;
268
+ props = {
269
+ ...common2,
270
+ query,
271
+ results: normalizeSearchResults(results),
272
+ total: number(output.total, output.totalCount)
273
+ };
274
+ } else {
275
+ if (["output-error", "output-denied", "approval-requested"].includes(
276
+ part.state
277
+ ))
278
+ return null;
279
+ const prompt = string(input.prompt, input.question);
280
+ if (!prompt) return null;
281
+ props = { ...input, prompt };
282
+ }
283
+ return {
284
+ type: "widget",
285
+ name,
286
+ id: part.toolCallId,
287
+ props,
288
+ interactive: name === "question" && part.state === "input-available"
289
+ };
290
+ }
291
+ function computeDiff(diff) {
292
+ let oldLine = 0, newLine = 0, inHunk = false, oldRemaining = 0, newRemaining = 0, additions = 0, deletions = 0;
293
+ const lines = diff.replace(/\r\n/g, "\n").split("\n").map((text) => {
294
+ var _a, _b;
295
+ const hunk = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(text);
296
+ if (hunk) {
297
+ oldLine = Number(hunk[1]);
298
+ newLine = Number(hunk[3]);
299
+ oldRemaining = Number((_a = hunk[2]) != null ? _a : 1);
300
+ newRemaining = Number((_b = hunk[4]) != null ? _b : 1);
301
+ inHunk = true;
302
+ return { kind: "header", text };
303
+ }
304
+ if (oldRemaining === 0 && newRemaining === 0) inHunk = false;
305
+ if (!inHunk && /^(diff --git|--- |\+\+\+ |\*\*\* )/.test(text)) {
306
+ inHunk = false;
307
+ return { kind: "header", text };
308
+ }
309
+ if (text.startsWith("@@")) {
310
+ inHunk = false;
311
+ return { kind: "header", text };
312
+ }
313
+ if (text.startsWith("+")) {
314
+ additions++;
315
+ if (inHunk) newRemaining--;
316
+ return { kind: "add", text, newLine: inHunk ? newLine++ : void 0 };
317
+ }
318
+ if (text.startsWith("-")) {
319
+ deletions++;
320
+ if (inHunk) oldRemaining--;
321
+ return {
322
+ kind: "remove",
323
+ text,
324
+ oldLine: inHunk ? oldLine++ : void 0
325
+ };
326
+ }
327
+ if (inHunk && text.startsWith(" ")) {
328
+ oldRemaining--;
329
+ newRemaining--;
330
+ return {
331
+ kind: "context",
332
+ text,
333
+ oldLine: oldLine++,
334
+ newLine: newLine++
335
+ };
336
+ }
337
+ return { kind: "header", text };
338
+ });
339
+ return { lines, additions, deletions };
340
+ }
341
+ function safeResultUrl(url) {
342
+ try {
343
+ const parsed = new URL(url != null ? url : "");
344
+ return ["https:", "http:"].includes(parsed.protocol) ? parsed.href : void 0;
345
+ } catch {
346
+ return void 0;
347
+ }
348
+ }
349
+ function computeTextDiff(before, after, path = "file") {
350
+ if (before === after) return "";
351
+ const split = (text) => text === "" ? [] : text.replace(/\r\n/g, "\n").replace(/\n$/, "").split("\n");
352
+ const oldLines = split(before), newLines = split(after);
353
+ let prefix = 0, suffix = 0;
354
+ while (prefix < oldLines.length && prefix < newLines.length && oldLines[prefix] === newLines[prefix])
355
+ prefix++;
356
+ while (suffix < oldLines.length - prefix && suffix < newLines.length - prefix && oldLines[oldLines.length - 1 - suffix] === newLines[newLines.length - 1 - suffix])
357
+ suffix++;
358
+ if (before.endsWith("\n") !== after.endsWith("\n")) suffix = 0;
359
+ if (prefix === oldLines.length && prefix === newLines.length) {
360
+ prefix = Math.max(0, prefix - 1);
361
+ suffix = 0;
362
+ }
363
+ const start = Math.max(0, prefix - 3), tail = Math.min(3, suffix);
364
+ const oldEnd = oldLines.length - suffix, newEnd = newLines.length - suffix;
365
+ const oldCount = oldEnd + tail - start, newCount = newEnd + tail - start;
366
+ const label = path.replace(/[\r\n]/g, "");
367
+ const body = [
368
+ ...oldLines.slice(start, prefix).map((line) => " " + line),
369
+ ...oldLines.slice(prefix, oldEnd).flatMap((line, index) => [
370
+ "-" + line,
371
+ ...prefix + index === oldLines.length - 1 && !before.endsWith("\n") ? ["\"] : []
372
+ ]),
373
+ ...newLines.slice(prefix, newEnd).flatMap((line, index) => [
374
+ "+" + line,
375
+ ...prefix + index === newLines.length - 1 && !after.endsWith("\n") ? ["\"] : []
376
+ ]),
377
+ ...oldLines.slice(oldEnd, oldEnd + tail).map((line) => " " + line)
378
+ ];
379
+ return [
380
+ `--- a/${label}`,
381
+ `+++ b/${label}`,
382
+ `@@ -${oldCount ? start + 1 : start},${oldCount} +${newCount ? start + 1 : start},${newCount} @@`,
383
+ ...body
384
+ ].join("\n");
385
+ }
386
+
387
+ // src/widgets/patch.tsx
388
+ var import_jsx_runtime3 = require("react/jsx-runtime");
389
+ function PatchWidget({
390
+ path = "File changes",
391
+ diff: rawDiff,
392
+ before,
393
+ after,
394
+ maxLines = 100,
395
+ ...props
396
+ }) {
397
+ const diff = (0, import_react2.useMemo)(
398
+ () => rawDiff != null ? rawDiff : before !== void 0 && after !== void 0 ? computeTextDiff(before, after, path) : "",
399
+ [rawDiff, before, after, path]
400
+ );
401
+ const [expanded, setExpanded] = (0, import_react2.useState)(false);
402
+ const { lines, additions, deletions } = (0, import_react2.useMemo)(
403
+ () => computeDiff(diff),
404
+ [diff]
405
+ );
406
+ const limit = Math.max(1, maxLines);
407
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
408
+ ToolFrame,
409
+ {
410
+ ...props,
411
+ label: "Patch",
412
+ title: path,
413
+ meta: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
414
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "chat-diff-add-count", children: [
415
+ "+",
416
+ additions
417
+ ] }),
418
+ " ",
419
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "chat-diff-remove-count", children: [
420
+ "\u2212",
421
+ deletions
422
+ ] })
423
+ ] }),
424
+ children: [
425
+ diff ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
426
+ "div",
427
+ {
428
+ className: "chat-code-preview chat-diff",
429
+ role: "region",
430
+ "aria-label": `Diff for ${path}`,
431
+ tabIndex: 0,
432
+ children: (expanded ? lines : lines.slice(0, limit)).map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "chat-code-line", "data-kind": line.kind, children: [
433
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "chat-line-number", "aria-hidden": "true", children: line.oldLine }),
434
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "chat-line-number", "aria-hidden": "true", children: line.newLine }),
435
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { children: line.text || " " })
436
+ ] }, index))
437
+ }
438
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "chat-widget-empty", children: "No changes supplied." }),
439
+ !expanded && lines.length > limit ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
440
+ "button",
441
+ {
442
+ className: "chat-widget-more",
443
+ type: "button",
444
+ onClick: () => setExpanded(true),
445
+ children: [
446
+ "Show full diff (",
447
+ lines.length,
448
+ " lines)"
449
+ ]
450
+ }
451
+ ) : null
452
+ ]
453
+ }
454
+ );
455
+ }
456
+
457
+ // src/widgets/search.tsx
458
+ var import_react3 = require("react");
459
+ var import_jsx_runtime4 = require("react/jsx-runtime");
460
+ function SearchWidget({
461
+ query,
462
+ results = [],
463
+ total,
464
+ maxResults = 5,
465
+ ...props
466
+ }) {
467
+ const [expanded, setExpanded] = (0, import_react3.useState)(false);
468
+ const limit = Math.max(1, maxResults);
469
+ const count = Math.max(results.length, total != null ? total : 0);
470
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
471
+ ToolFrame,
472
+ {
473
+ ...props,
474
+ label: "Search",
475
+ title: query,
476
+ meta: `${count} ${count === 1 ? "result" : "results"}`,
477
+ children: [
478
+ !results.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "chat-widget-empty", children: props.state === "running" ? "Searching\u2026" : "No results found." }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ol", { className: "chat-search-results", children: (expanded ? results : results.slice(0, limit)).map(
479
+ (result, index) => {
480
+ const href = safeResultUrl(result.url);
481
+ const label = /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
482
+ result.title || result.path,
483
+ result.line ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "chat-search-line", children: [
484
+ ":",
485
+ result.line
486
+ ] }) : null
487
+ ] });
488
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("li", { children: [
489
+ href ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href, target: "_blank", rel: "noreferrer", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "chat-search-path", children: label }),
490
+ result.text ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: result.text }) : null
491
+ ] }, `${result.path}-${result.line}-${index}`);
492
+ }
493
+ ) }),
494
+ !expanded && results.length > limit ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
495
+ "button",
496
+ {
497
+ className: "chat-widget-more",
498
+ type: "button",
499
+ onClick: () => setExpanded(true),
500
+ children: [
501
+ "Show ",
502
+ results.length - limit,
503
+ " more results"
504
+ ]
505
+ }
506
+ ) : null
507
+ ]
508
+ }
509
+ );
510
+ }
511
+
512
+ // src/widgets/question.tsx
513
+ var import_react4 = require("react");
514
+ var import_lucide_react2 = require("lucide-react");
515
+ var import_jsx_runtime5 = require("react/jsx-runtime");
516
+ function QuestionWidget({
517
+ prompt,
518
+ description,
519
+ options = [],
520
+ multiple = false,
521
+ allowCustom = false,
522
+ disabled = false,
523
+ onSubmit,
524
+ className = ""
525
+ }) {
526
+ const id = (0, import_react4.useId)();
527
+ const [selected, setSelected] = (0, import_react4.useState)([]), [text, setText] = (0, import_react4.useState)("");
528
+ const [status, setStatus] = (0, import_react4.useState)("idle");
529
+ const [error, setError] = (0, import_react4.useState)();
530
+ const submitting = (0, import_react4.useRef)(false);
531
+ const choices = options.map(
532
+ (option) => typeof option === "string" ? { label: option, value: option } : option
533
+ );
534
+ const locked = disabled || status !== "idle" || !onSubmit;
535
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
536
+ "form",
537
+ {
538
+ className: `chat-prebuilt chat-question ${className}`,
539
+ "aria-labelledby": `${id}-prompt`,
540
+ onSubmit: async (event) => {
541
+ event.preventDefault();
542
+ if (locked || submitting.current || !selected.length && !text.trim())
543
+ return;
544
+ submitting.current = true;
545
+ setStatus("sending");
546
+ setError(void 0);
547
+ try {
548
+ await (onSubmit == null ? void 0 : onSubmit({
549
+ values: selected,
550
+ ...text.trim() ? { text: text.trim() } : {}
551
+ }));
552
+ setStatus("sent");
553
+ } catch (cause) {
554
+ setError(
555
+ cause instanceof Error ? cause.message : "Could not send your answer. Try again."
556
+ );
557
+ setStatus("idle");
558
+ } finally {
559
+ submitting.current = false;
560
+ }
561
+ },
562
+ children: [
563
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "chat-question-eyebrow", children: "Your input" }),
564
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { id: `${id}-prompt`, children: prompt }),
565
+ description ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "chat-question-description", children: description }) : null,
566
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("fieldset", { disabled: locked, children: [
567
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("legend", { className: "chat-sr-only", children: multiple ? "Select one or more options" : "Select an option" }),
568
+ choices.map((option, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
569
+ "label",
570
+ {
571
+ className: "chat-question-option",
572
+ "data-selected": selected.includes(option.value),
573
+ children: [
574
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
575
+ "input",
576
+ {
577
+ type: multiple ? "checkbox" : "radio",
578
+ name: id,
579
+ value: option.value,
580
+ checked: selected.includes(option.value),
581
+ onChange: () => setSelected(
582
+ (current) => multiple ? current.includes(option.value) ? current.filter((value) => value !== option.value) : [...current, option.value] : [option.value]
583
+ )
584
+ }
585
+ ),
586
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
587
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "chat-question-option-title", children: [
588
+ option.label,
589
+ option.recommended ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { children: "Recommended" }) : null
590
+ ] }),
591
+ option.description ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "chat-question-option-description", children: option.description }) : null
592
+ ] })
593
+ ]
594
+ },
595
+ `${option.value}-${index}`
596
+ )),
597
+ allowCustom || !choices.length ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "chat-question-custom", children: [
598
+ choices.length ? "Additional context" : "Your answer",
599
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
600
+ "textarea",
601
+ {
602
+ rows: 2,
603
+ value: text,
604
+ onChange: (event) => setText(event.target.value),
605
+ placeholder: "Type your answer\u2026"
606
+ }
607
+ )
608
+ ] }) : null
609
+ ] }),
610
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("footer", { children: [
611
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { role: "status", children: status === "sent" ? "Answer sent" : status === "sending" ? "Sending\u2026" : multiple ? "Choose one or more" : choices.length ? "Choose and confirm" : "Write and confirm" }),
612
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
613
+ "button",
614
+ {
615
+ type: "submit",
616
+ disabled: locked || !selected.length && !text.trim(),
617
+ children: [
618
+ status === "sent" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.Check, { size: 14, "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.ArrowUp, { size: 14, "aria-hidden": "true" }),
619
+ status === "sent" ? "Submitted" : "Confirm"
620
+ ]
621
+ }
622
+ )
623
+ ] }),
624
+ error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "chat-widget-error", role: "alert", children: error }) : null
625
+ ]
626
+ }
627
+ );
628
+ }
629
+
630
+ // src/widgets/registry.tsx
631
+ var import_protocol3 = require("@sarchauhan/protocol");
632
+
633
+ // src/widgets/artifact.tsx
634
+ var import_react6 = require("react");
635
+ var import_lucide_react4 = require("lucide-react");
636
+
637
+ // src/widgets/responsive-detail.tsx
638
+ var import_react5 = require("react");
639
+ var import_radix_ui = require("radix-ui");
640
+ var import_lucide_react3 = require("lucide-react");
641
+ var import_jsx_runtime6 = require("react/jsx-runtime");
642
+ function ResponsiveDetail({ title, description = "Details from this conversation", trigger, children }) {
643
+ const origin = (0, import_react5.useRef)(null);
644
+ const [presentation, setPresentation] = (0, import_react5.useState)({ theme: "light", style: {} });
645
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: origin, className: "chat-detail-origin", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_radix_ui.Dialog.Root, { onOpenChange: (open) => {
646
+ var _a, _b;
647
+ if (!open || !origin.current) return;
648
+ const host = (_a = origin.current.closest(".chat-root")) != null ? _a : origin.current;
649
+ const computed = window.getComputedStyle(host);
650
+ const tokens = {};
651
+ for (let index = 0; index < computed.length; index++) {
652
+ const name = computed.item(index);
653
+ if (name.startsWith("--chat-")) tokens[name] = computed.getPropertyValue(name);
654
+ }
655
+ const requested = host.getAttribute("data-theme");
656
+ const dark = requested === "dark" || requested === "system" && ((_b = window.matchMedia) == null ? void 0 : _b.call(window, "(prefers-color-scheme: dark)").matches);
657
+ setPresentation({ theme: dark ? "dark" : "light", style: tokens });
658
+ }, children: [
659
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_radix_ui.Dialog.Trigger, { asChild: true, children: trigger }),
660
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_radix_ui.Dialog.Portal, { children: [
661
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_radix_ui.Dialog.Overlay, { className: "chat-detail-overlay" }),
662
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_radix_ui.Dialog.Content, { className: "chat-root chat-detail-panel", "data-theme": presentation.theme, style: presentation.style, children: [
663
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "chat-detail-handle", "aria-hidden": "true" }),
664
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("header", { className: "chat-detail-header", children: [
665
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
666
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_radix_ui.Dialog.Title, { className: "chat-detail-title", children: title }),
667
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_radix_ui.Dialog.Description, { className: "chat-detail-description", children: description })
668
+ ] }),
669
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_radix_ui.Dialog.Close, { className: "chat-detail-close", "aria-label": "Close details", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.X, { size: 18, "aria-hidden": "true" }) })
670
+ ] }),
671
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "chat-detail-body", children })
672
+ ] })
673
+ ] })
674
+ ] }) });
675
+ }
676
+
677
+ // src/widgets/artifact.tsx
678
+ var import_jsx_runtime7 = require("react/jsx-runtime");
679
+ function safeArtifactUrl(value, image = false) {
680
+ if (!value || /[\u0000-\u0020\u007f]/.test(value)) return void 0;
681
+ if (/^blob:/i.test(value)) {
682
+ try {
683
+ new URL(value);
684
+ return value;
685
+ } catch {
686
+ return void 0;
687
+ }
688
+ }
689
+ if (image && /^data:image\/(?:png|jpeg|gif|webp|avif);base64,[a-z0-9+/=]+$/i.test(value)) return value;
690
+ try {
691
+ const parsed = new URL(value, "https://chat.invalid");
692
+ if (!["https:", "http:"].includes(parsed.protocol)) return void 0;
693
+ return value;
694
+ } catch {
695
+ return void 0;
696
+ }
697
+ }
698
+ function formatArtifactSize(bytes) {
699
+ if (bytes === void 0 || !Number.isFinite(bytes) || bytes < 0) return void 0;
700
+ if (bytes < 1024) return bytes + " B";
701
+ if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
702
+ return (bytes / (1024 * 1024)).toFixed(1) + " MB";
703
+ }
704
+ function ArtifactWidget({ artifact, className = "" }) {
705
+ var _a;
706
+ const { filename, mediaType, content, sizeBytes, error } = artifact;
707
+ const state = (_a = artifact.status) != null ? _a : "ready";
708
+ const image = mediaType.startsWith("image/");
709
+ const [failedUrl, setFailedUrl] = (0, import_react6.useState)();
710
+ const previewUrl = image ? safeArtifactUrl(artifact.url, true) : void 0;
711
+ const link = safeArtifactUrl(artifact.url, image);
712
+ const ready = state === "ready";
713
+ const preview = ready && (previewUrl && failedUrl !== previewUrl || content !== void 0);
714
+ const Icon = image ? import_lucide_react4.Image : import_lucide_react4.FileText;
715
+ const label = state === "creating" ? "Creating\u2026" : state === "error" ? "Could not create file" : "Created";
716
+ const metadata = [mediaType, formatArtifactSize(sizeBytes)].filter(Boolean).join(" \xB7 ");
717
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "chat-prebuilt chat-artifact " + className, "aria-label": "Artifact: " + filename, "data-state": state, children: [
718
+ ready && previewUrl && failedUrl !== previewUrl ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "chat-artifact-thumbnail", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("img", { src: previewUrl, alt: filename, loading: "lazy", onError: () => setFailedUrl(previewUrl) }) }) : null,
719
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "chat-artifact-row", children: [
720
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "chat-artifact-icon", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { size: 20, "aria-hidden": "true" }) }),
721
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "chat-artifact-heading", children: [
722
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { title: filename, children: filename }),
723
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: metadata })
724
+ ] }),
725
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "chat-artifact-state", role: "status", children: label })
726
+ ] }),
727
+ state === "error" && error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "chat-widget-error", role: "alert", children: error }) : null,
728
+ ready && image && previewUrl && failedUrl === previewUrl ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "chat-widget-empty", children: "Image preview unavailable." }) : null,
729
+ ready && (preview || link) ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("footer", { className: "chat-artifact-actions", children: [
730
+ preview ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ResponsiveDetail, { title: filename, description: metadata, trigger: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", children: "Preview" }), children: image && previewUrl && failedUrl !== previewUrl ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("img", { className: "chat-artifact-full-image", src: previewUrl, alt: filename, onError: () => setFailedUrl(previewUrl) }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("pre", { className: "chat-artifact-text", tabIndex: 0, children: content }) }) : null,
731
+ link ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
732
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("a", { href: link, target: "_blank", rel: "noreferrer", children: [
733
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.ExternalLink, { size: 14, "aria-hidden": "true" }),
734
+ "Open"
735
+ ] }),
736
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("a", { href: link, download: filename, target: "_blank", rel: "noreferrer", children: [
737
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.Download, { size: 14, "aria-hidden": "true" }),
738
+ "Download"
739
+ ] })
740
+ ] }) : null
741
+ ] }) : null
742
+ ] });
743
+ }
744
+ function ArtifactsWidget({ artifacts, className = "" }) {
745
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "chat-artifacts " + className, children: artifacts.map((artifact) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ArtifactWidget, { artifact }, artifact.id)) });
746
+ }
747
+
748
+ // src/widgets/subagent.tsx
749
+ var import_react15 = require("react");
750
+ var import_lucide_react7 = require("lucide-react");
751
+
752
+ // src/components/Message/message.content.tsx
753
+ var import_protocol2 = require("@sarchauhan/protocol");
754
+ var import_lucide_react6 = require("lucide-react");
755
+ var import_react14 = require("react");
756
+
757
+ // src/lib/message/segment.ts
758
+ var splitThinkingSegments = (content) => {
759
+ const segments = [];
760
+ let cursor = 0;
761
+ while (cursor < content.length) {
762
+ const openingIndex = content.indexOf("<thinking>", cursor);
763
+ if (openingIndex === -1) {
764
+ segments.push({
765
+ type: "markdown",
766
+ content: content.slice(cursor)
767
+ });
768
+ break;
769
+ }
770
+ if (openingIndex > cursor) {
771
+ segments.push({
772
+ type: "markdown",
773
+ content: content.slice(cursor, openingIndex)
774
+ });
775
+ }
776
+ const thinkingStart = openingIndex + "<thinking>".length;
777
+ const closingIndex = content.indexOf("</thinking>", thinkingStart);
778
+ if (closingIndex === -1) {
779
+ segments.push({
780
+ type: "thinking",
781
+ content: content.slice(thinkingStart).trim(),
782
+ isComplete: false
783
+ });
784
+ break;
785
+ }
786
+ segments.push({
787
+ type: "thinking",
788
+ content: content.slice(thinkingStart, closingIndex).trim(),
789
+ isComplete: true
790
+ });
791
+ cursor = closingIndex + "</thinking>".length;
792
+ }
793
+ if (!segments.length) {
794
+ return [{ type: "markdown", content }];
795
+ }
796
+ return segments;
797
+ };
798
+
799
+ // src/lib/message/user.ts
800
+ var REFERENCE_PREFIX = "Use the following selected references as context:\n\n";
801
+ var USER_MESSAGE_MARKER = "\n\nUser message:\n";
802
+ var REFERENCE_PATTERN = /<reference \d+>\n([\s\S]*?)\n<\/reference \d+>/g;
803
+ var parseUserReferenceMessage = (content) => {
804
+ if (!content.startsWith(REFERENCE_PREFIX)) {
805
+ return null;
806
+ }
807
+ const markerIndex = content.indexOf(USER_MESSAGE_MARKER);
808
+ if (markerIndex === -1) {
809
+ return null;
810
+ }
811
+ const references = [...content.slice(REFERENCE_PREFIX.length, markerIndex).matchAll(REFERENCE_PATTERN)].map((match) => match[1].trim()).filter(Boolean);
812
+ return references.length ? { references, message: content.slice(markerIndex + USER_MESSAGE_MARKER.length) } : null;
813
+ };
814
+
815
+ // src/lib/utils.ts
816
+ var import_clsx = require("clsx");
817
+ var import_tailwind_merge = require("tailwind-merge");
818
+ function cn(...inputs) {
819
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
820
+ }
821
+
822
+ // src/motion/classes.ts
823
+ var motion = {
824
+ textSwap: "t-text-swap",
825
+ isExit: "is-exit",
826
+ isEnterStart: "is-enter-start",
827
+ iconSwap: "t-icon-swap",
828
+ icon: "t-icon",
829
+ successCheck: "t-success-check",
830
+ dropdown: "t-dropdown",
831
+ isOpen: "is-open",
832
+ isClosing: "is-closing",
833
+ inputWrap: "t-input-wrap",
834
+ input: "t-input",
835
+ errorMsg: "t-error-msg",
836
+ isError: "is-error",
837
+ isShaking: "is-shaking"
838
+ };
839
+
840
+ // src/motion/helpers.ts
841
+ var CHAT_ROOT = ".chat-root";
842
+ var prefersReducedMotion = () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
843
+ var motionRoot = (node) => {
844
+ var _a;
845
+ return (_a = node == null ? void 0 : node.closest(CHAT_ROOT)) != null ? _a : typeof document !== "undefined" ? document.querySelector(CHAT_ROOT) : null;
846
+ };
847
+ var readRaw = (name, node) => {
848
+ const root = motionRoot(node);
849
+ if (!root) {
850
+ return "";
851
+ }
852
+ return getComputedStyle(root).getPropertyValue(name);
853
+ };
854
+ var readDurationMs = (name, fallback, node) => {
855
+ const value = parseFloat(readRaw(name, node));
856
+ return Number.isFinite(value) ? value : fallback;
857
+ };
858
+ var revertTimers = /* @__PURE__ */ new WeakMap();
859
+ var shakeTimers = /* @__PURE__ */ new WeakMap();
860
+ var triggerErrorShake = (wrap, options) => {
861
+ var _a;
862
+ const input = wrap.matches(`.${motion.input}`) ? wrap : (_a = wrap.querySelector(`.${motion.input}`)) != null ? _a : wrap;
863
+ wrap.classList.add(motion.isError);
864
+ input.classList.add(motion.isError);
865
+ input.classList.remove(motion.isShaking);
866
+ void input.offsetWidth;
867
+ input.classList.add(motion.isShaking);
868
+ const existingShake = shakeTimers.get(input);
869
+ if (existingShake) {
870
+ window.clearTimeout(existingShake);
871
+ }
872
+ const shakeMs = readDurationMs("--shake-dur-a", 80, wrap) * 2 + readDurationMs("--shake-dur-b", 60, wrap) * 2;
873
+ shakeTimers.set(
874
+ input,
875
+ window.setTimeout(() => {
876
+ input.classList.remove(motion.isShaking);
877
+ shakeTimers.delete(input);
878
+ }, shakeMs + 20)
879
+ );
880
+ const existingRevert = revertTimers.get(wrap);
881
+ if (existingRevert) {
882
+ window.clearTimeout(existingRevert);
883
+ revertTimers.delete(wrap);
884
+ }
885
+ if ((options == null ? void 0 : options.revert) === false) {
886
+ return;
887
+ }
888
+ const hold = readDurationMs("--revert-hold", 3e3, wrap);
889
+ revertTimers.set(
890
+ wrap,
891
+ window.setTimeout(() => {
892
+ revertTimers.delete(wrap);
893
+ wrap.classList.remove(motion.isError);
894
+ input.classList.remove(motion.isError);
895
+ }, shakeMs + hold)
896
+ );
897
+ };
898
+ var calibrateCheckPath = (path) => {
899
+ const len = Math.ceil(path.getTotalLength());
900
+ path.style.strokeDasharray = String(len);
901
+ path.style.strokeDashoffset = String(len);
902
+ };
903
+
904
+ // src/motion/text-swap.tsx
905
+ var import_react7 = require("react");
906
+ var import_jsx_runtime8 = require("react/jsx-runtime");
907
+ function TextSwap({ text, className, ...props }) {
908
+ const ref = (0, import_react7.useRef)(null);
909
+ const shownRef = (0, import_react7.useRef)(text);
910
+ (0, import_react7.useEffect)(() => {
911
+ const el = ref.current;
912
+ if (!el || shownRef.current === text) {
913
+ return;
914
+ }
915
+ if (prefersReducedMotion()) {
916
+ shownRef.current = text;
917
+ el.textContent = text;
918
+ return;
919
+ }
920
+ const dur = readDurationMs("--text-swap-dur", 200, el);
921
+ el.classList.add(motion.isExit);
922
+ const timer = window.setTimeout(() => {
923
+ el.classList.remove(motion.isExit);
924
+ el.classList.add(motion.isEnterStart);
925
+ el.textContent = text;
926
+ shownRef.current = text;
927
+ void el.offsetHeight;
928
+ el.classList.remove(motion.isEnterStart);
929
+ }, dur);
930
+ return () => window.clearTimeout(timer);
931
+ }, [text]);
932
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { ref, className: cn(motion.textSwap, className), ...props, children: shownRef.current });
933
+ }
934
+
935
+ // src/components/Widget/widget.context.tsx
936
+ var import_react8 = require("react");
937
+ var import_jsx_runtime9 = require("react/jsx-runtime");
938
+ function readWidgetValue(value, props, controls) {
939
+ return typeof value === "function" ? value(props, controls) : value;
940
+ }
941
+ function getWidgetShellProps(definition, props, controls) {
942
+ var _a;
943
+ const title = readWidgetValue(definition.title, props, controls);
944
+ return {
945
+ label: (_a = readWidgetValue(definition.label, props, controls)) != null ? _a : definition.name.replace(/[-_]/g, " "),
946
+ title: title != null ? title : definition.name,
947
+ status: readWidgetValue(definition.status, props, controls),
948
+ meta: readWidgetValue(definition.meta, props, controls),
949
+ className: readWidgetValue(definition.className, props, controls)
950
+ };
951
+ }
952
+ function isWidgetDefinition(entry) {
953
+ return Boolean(entry && typeof entry === "object" && "component" in entry);
954
+ }
955
+ var WidgetContext = (0, import_react8.createContext)(null);
956
+ function useWidgets() {
957
+ const context = (0, import_react8.useContext)(WidgetContext);
958
+ if (!context) {
959
+ return {
960
+ widgets: prebuiltWidgets,
961
+ respondToWidget: async () => void 0,
962
+ disabled: true
963
+ };
964
+ }
965
+ return context;
966
+ }
967
+ function resolveWidgetPart(part, registry) {
968
+ var _a;
969
+ return (_a = registry[part.name]) != null ? _a : null;
970
+ }
971
+
972
+ // src/ui/button.tsx
973
+ var import_class_variance_authority = require("class-variance-authority");
974
+ var import_radix_ui2 = require("radix-ui");
975
+ var import_jsx_runtime10 = require("react/jsx-runtime");
976
+ var buttonVariants = (0, import_class_variance_authority.cva)(
977
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
978
+ {
979
+ variants: {
980
+ variant: {
981
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
982
+ destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
983
+ outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
984
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
985
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
986
+ link: "text-primary underline-offset-4 hover:underline"
987
+ },
988
+ size: {
989
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
990
+ xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
991
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
992
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
993
+ icon: "size-9",
994
+ "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
995
+ "icon-sm": "size-8",
996
+ "icon-lg": "size-10"
997
+ }
998
+ },
999
+ defaultVariants: {
1000
+ variant: "default",
1001
+ size: "default"
1002
+ }
1003
+ }
1004
+ );
1005
+ function Button({
1006
+ className,
1007
+ variant = "default",
1008
+ size = "default",
1009
+ asChild = false,
1010
+ skeleton = false,
1011
+ disabled,
1012
+ ...props
1013
+ }) {
1014
+ const Comp = asChild ? import_radix_ui2.Slot.Root : "button";
1015
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1016
+ Comp,
1017
+ {
1018
+ "data-slot": "button",
1019
+ "data-variant": variant,
1020
+ "data-size": size,
1021
+ "data-skeleton": skeleton ? "true" : void 0,
1022
+ "aria-busy": skeleton ? true : void 0,
1023
+ disabled: skeleton || disabled,
1024
+ className: cn(buttonVariants({ variant, size, className })),
1025
+ ...props
1026
+ }
1027
+ );
1028
+ }
1029
+
1030
+ // src/components/Message/message.skeleton.tsx
1031
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1032
+ var TextSkeleton = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "chat-text-skeleton", role: "status", "aria-label": "Assistant is writing", children: [
1033
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "chat-skeleton-bar" }),
1034
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "chat-skeleton-bar" }),
1035
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "chat-skeleton-bar chat-skeleton-bar-short" })
1036
+ ] });
1037
+ var WidgetActionSkeleton = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "chat-widget-action-skeleton", "aria-label": "Widget actions are loading", children: [
1038
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Button, { skeleton: true, size: "sm", variant: "secondary", type: "button", tabIndex: -1, "aria-hidden": "true", children: "Confirm" }),
1039
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Button, { skeleton: true, size: "sm", variant: "outline", type: "button", tabIndex: -1, "aria-hidden": "true", children: "Cancel" })
1040
+ ] });
1041
+
1042
+ // src/components/Widget/widget.renderer.tsx
1043
+ var import_react9 = require("react");
1044
+
1045
+ // src/components/Widget/base.widget.tsx
1046
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1047
+ function BaseWidget({
1048
+ label,
1049
+ title,
1050
+ status,
1051
+ meta,
1052
+ className,
1053
+ children
1054
+ }) {
1055
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { className: cn("chat-widget-card", className), "aria-label": label, children: [
1056
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("header", { className: "chat-widget-header", children: [
1057
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "chat-widget-heading", children: [
1058
+ label ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "chat-widget-label-row", children: [
1059
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "chat-widget-status-dot", "aria-hidden": "true" }),
1060
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "chat-widget-label", children: label })
1061
+ ] }) : null,
1062
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "chat-widget-title", children: title })
1063
+ ] }),
1064
+ status ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "chat-widget-status", children: status }) : null
1065
+ ] }),
1066
+ children ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "chat-widget-body", children }) : null,
1067
+ meta ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "chat-widget-meta", children: meta }) : null
1068
+ ] });
1069
+ }
1070
+
1071
+ // src/components/Widget/widget.renderer.tsx
1072
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1073
+ function WidgetRenderer({
1074
+ part,
1075
+ pending = false
1076
+ }) {
1077
+ const { widgets, respondToWidget, disabled } = useWidgets();
1078
+ const entry = resolveWidgetPart(part, widgets);
1079
+ const [submitted, setSubmitted] = (0, import_react9.useState)(false);
1080
+ const responsePending = (0, import_react9.useRef)(false);
1081
+ const widgetDisabled = disabled || submitted;
1082
+ const respond = async (value, label, actionId) => {
1083
+ if (!part.interactive || disabled || submitted || responsePending.current) {
1084
+ return;
1085
+ }
1086
+ responsePending.current = true;
1087
+ setSubmitted(true);
1088
+ try {
1089
+ await respondToWidget({
1090
+ widgetId: part.id,
1091
+ name: part.name,
1092
+ actionId,
1093
+ value,
1094
+ label
1095
+ });
1096
+ } catch (error) {
1097
+ setSubmitted(false);
1098
+ throw error;
1099
+ } finally {
1100
+ responsePending.current = false;
1101
+ }
1102
+ };
1103
+ const controls = {
1104
+ widgetId: part.id,
1105
+ widgetName: part.name,
1106
+ interactive: Boolean(part.interactive),
1107
+ disabled: widgetDisabled,
1108
+ respond,
1109
+ respondWith: async (response) => {
1110
+ await respond(response.value, response.label, response.actionId);
1111
+ }
1112
+ };
1113
+ const frame = (node) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "chat-widget", "data-pending": pending ? "true" : void 0, children: [
1114
+ node,
1115
+ pending ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(WidgetActionSkeleton, {}) : null
1116
+ ] });
1117
+ if (!entry) {
1118
+ return frame(
1119
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1120
+ BaseWidget,
1121
+ {
1122
+ label: "Unhandled widget",
1123
+ title: part.name,
1124
+ status: "Raw props",
1125
+ className: "chat-widget-missing",
1126
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("pre", { className: "agent-tool-code", children: JSON.stringify(part.props, null, 2) })
1127
+ }
1128
+ )
1129
+ );
1130
+ }
1131
+ if (isWidgetDefinition(entry)) {
1132
+ const Component2 = entry.component;
1133
+ const content = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Component2, { ...part.props, widget: controls });
1134
+ if (entry.shell === false) {
1135
+ return frame(content);
1136
+ }
1137
+ return frame(
1138
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BaseWidget, { ...getWidgetShellProps(entry, part.props, controls), children: content })
1139
+ );
1140
+ }
1141
+ const Component = entry;
1142
+ return frame(
1143
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1144
+ Component,
1145
+ {
1146
+ id: part.id,
1147
+ name: part.name,
1148
+ props: part.props,
1149
+ interactive: part.interactive,
1150
+ disabled: widgetDisabled,
1151
+ onRespond: async (response) => {
1152
+ if (!part.interactive || disabled || submitted || responsePending.current) {
1153
+ return;
1154
+ }
1155
+ responsePending.current = true;
1156
+ setSubmitted(true);
1157
+ try {
1158
+ await respondToWidget(response);
1159
+ } catch (error) {
1160
+ setSubmitted(false);
1161
+ throw error;
1162
+ } finally {
1163
+ responsePending.current = false;
1164
+ }
1165
+ }
1166
+ }
1167
+ )
1168
+ );
1169
+ }
1170
+
1171
+ // src/components/Message/message.markdown.tsx
1172
+ var import_react11 = require("react");
1173
+ var import_code_markdown = require("@sarchauhan/code-markdown");
1174
+ var import_react_markdown = __toESM(require("react-markdown"));
1175
+ var import_remark_gfm = __toESM(require("remark-gfm"));
1176
+
1177
+ // src/theme/theme.context.tsx
1178
+ var import_react10 = require("react");
1179
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1180
+ var ThemeContext = (0, import_react10.createContext)(null);
1181
+ function useTheme() {
1182
+ const context = (0, import_react10.useContext)(ThemeContext);
1183
+ if (!context) {
1184
+ throw new Error("useTheme must be used inside ThemeProvider");
1185
+ }
1186
+ return context;
1187
+ }
1188
+
1189
+ // src/components/Message/message.markdown.theme.ts
1190
+ var chatCodeThemes = {
1191
+ light: {
1192
+ name: "chat-light",
1193
+ shikiTheme: "github-light",
1194
+ colors: {
1195
+ background: "#ffffff",
1196
+ foreground: "#0d0d0d",
1197
+ comment: "#6e6e80",
1198
+ keyword: "#9b174c",
1199
+ string: "#166534",
1200
+ function: "#1d4ed8",
1201
+ variable: "#0d0d0d",
1202
+ number: "#7c3aed",
1203
+ operator: "#9b174c",
1204
+ punctuation: "#6e6e80",
1205
+ type: "#0369a1",
1206
+ tag: "#166534",
1207
+ attribute: "#1d4ed8",
1208
+ constant: "#b45309",
1209
+ surface: "#f7f7f8",
1210
+ overlay: "#d8d8df",
1211
+ subtext: "#6e6e80"
1212
+ }
1213
+ },
1214
+ dark: {
1215
+ name: "chat-dark",
1216
+ shikiTheme: "github-dark",
1217
+ colors: {
1218
+ background: "#212121",
1219
+ foreground: "#ececec",
1220
+ comment: "#8f8f8f",
1221
+ keyword: "#ff7b72",
1222
+ string: "#a5d6a7",
1223
+ function: "#79c0ff",
1224
+ variable: "#ececec",
1225
+ number: "#d2a8ff",
1226
+ operator: "#ff7b72",
1227
+ punctuation: "#b4b4b4",
1228
+ type: "#79c0ff",
1229
+ tag: "#7ee787",
1230
+ attribute: "#79c0ff",
1231
+ constant: "#ffa657",
1232
+ surface: "#2f2f2f",
1233
+ overlay: "#454545",
1234
+ subtext: "#b4b4b4"
1235
+ }
1236
+ }
1237
+ };
1238
+
1239
+ // src/components/Message/message.markdown.tsx
1240
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1241
+ var markdownPlugins = {
1242
+ remark: [import_remark_gfm.default],
1243
+ rehype: []
1244
+ };
1245
+ var SUPPORTED_LANGUAGES = /* @__PURE__ */ new Set([
1246
+ "c",
1247
+ "h",
1248
+ "cpp",
1249
+ "cxx",
1250
+ "cc",
1251
+ "hpp",
1252
+ "hxx",
1253
+ "go",
1254
+ "javascript",
1255
+ "js",
1256
+ "jsx",
1257
+ "mjs",
1258
+ "python",
1259
+ "py",
1260
+ "rust",
1261
+ "rs",
1262
+ "typescript",
1263
+ "ts",
1264
+ "tsx"
1265
+ ]);
1266
+ var isSupportedLanguage = (value) => SUPPORTED_LANGUAGES.has(value);
1267
+ var getCodeLanguage = (className) => {
1268
+ var _a;
1269
+ const match = className == null ? void 0 : className.match(/language-([\w-]+)/);
1270
+ const language = (_a = match == null ? void 0 : match[1]) == null ? void 0 : _a.toLowerCase();
1271
+ return language && isSupportedLanguage(language) ? language : "typescript";
1272
+ };
1273
+ var getTextContent = (value) => {
1274
+ if (typeof value === "string" || typeof value === "number") {
1275
+ return String(value);
1276
+ }
1277
+ if (Array.isArray(value)) {
1278
+ return value.map(getTextContent).join("");
1279
+ }
1280
+ return "";
1281
+ };
1282
+ var MarkdownCodeBlock = ({
1283
+ code,
1284
+ language
1285
+ }) => {
1286
+ const { resolvedTheme } = useTheme();
1287
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1288
+ import_code_markdown.CodeMarkdown,
1289
+ {
1290
+ className: "chat-code-markdown",
1291
+ language,
1292
+ theme: chatCodeThemes[resolvedTheme],
1293
+ showCopyButton: true,
1294
+ showLineNumbers: true,
1295
+ showLanguage: true,
1296
+ children: code
1297
+ }
1298
+ );
1299
+ };
1300
+ var MarkdownPre = ({ className, children }) => {
1301
+ const child = import_react11.Children.toArray(children)[0];
1302
+ const code = (0, import_react11.isValidElement)(child) ? getTextContent(child.props.children) : getTextContent(children);
1303
+ const codeClassName = (0, import_react11.isValidElement)(child) ? child.props.className : void 0;
1304
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: cn("my-5", className), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1305
+ MarkdownCodeBlock,
1306
+ {
1307
+ language: getCodeLanguage(codeClassName),
1308
+ code: code.replace(/\n$/, "")
1309
+ }
1310
+ ) });
1311
+ };
1312
+ var markdownComponents = {
1313
+ a: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1314
+ "a",
1315
+ {
1316
+ className: cn(
1317
+ "font-medium text-primary underline underline-offset-2 decoration-primary/30 decoration-1 hover:decoration-primary/70",
1318
+ className
1319
+ ),
1320
+ target: "_blank",
1321
+ rel: "noreferrer noopener",
1322
+ ...props
1323
+ }
1324
+ ),
1325
+ p: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1326
+ "p",
1327
+ {
1328
+ className: cn("my-[0.85em] text-inherit chat-text-body first:mt-0 last:mb-0", className),
1329
+ style: { fontSize: "var(--chat-body-size)", lineHeight: "var(--chat-body-leading)" },
1330
+ ...props
1331
+ }
1332
+ ),
1333
+ h1: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1334
+ "h1",
1335
+ {
1336
+ className: cn("mt-8 mb-3 chat-text-heading-1", className),
1337
+ style: {
1338
+ fontSize: "var(--chat-heading-1-size)",
1339
+ lineHeight: "var(--chat-heading-1-leading)",
1340
+ fontWeight: "var(--chat-heading-1-weight)",
1341
+ letterSpacing: "var(--chat-heading-1-tracking)"
1342
+ },
1343
+ ...props
1344
+ }
1345
+ ),
1346
+ h2: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1347
+ "h2",
1348
+ {
1349
+ className: cn("mt-8 mb-3", className),
1350
+ style: {
1351
+ fontSize: "var(--chat-fs-18)",
1352
+ lineHeight: "var(--chat-leading-tight)",
1353
+ fontWeight: "var(--chat-weight-semibold)",
1354
+ letterSpacing: "var(--chat-tracking-tight)"
1355
+ },
1356
+ ...props
1357
+ }
1358
+ ),
1359
+ h3: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1360
+ "h3",
1361
+ {
1362
+ className: cn("mt-6 mb-2", className),
1363
+ style: {
1364
+ fontSize: "var(--chat-fs-16)",
1365
+ lineHeight: "var(--chat-leading-tight)",
1366
+ fontWeight: "var(--chat-weight-semibold)",
1367
+ letterSpacing: "var(--chat-tracking-tight)"
1368
+ },
1369
+ ...props
1370
+ }
1371
+ ),
1372
+ h4: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1373
+ "h4",
1374
+ {
1375
+ className: cn("mt-6 mb-2", className),
1376
+ style: {
1377
+ fontSize: "var(--chat-fs-15)",
1378
+ lineHeight: "var(--chat-leading-tight)",
1379
+ fontWeight: "var(--chat-weight-semibold)",
1380
+ letterSpacing: "var(--chat-tracking-normal)"
1381
+ },
1382
+ ...props
1383
+ }
1384
+ ),
1385
+ ul: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1386
+ "ul",
1387
+ {
1388
+ className: cn("my-4 list-disc space-y-2 pl-6 chat-text-body", className),
1389
+ style: { fontSize: "var(--chat-body-size)", lineHeight: "var(--chat-body-leading)" },
1390
+ ...props
1391
+ }
1392
+ ),
1393
+ ol: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1394
+ "ol",
1395
+ {
1396
+ className: cn("my-4 list-decimal space-y-2 pl-6 chat-text-body", className),
1397
+ style: { fontSize: "var(--chat-body-size)", lineHeight: "var(--chat-body-leading)" },
1398
+ ...props
1399
+ }
1400
+ ),
1401
+ li: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1402
+ "li",
1403
+ {
1404
+ className: cn("pl-1", className),
1405
+ style: { lineHeight: "var(--chat-leading-normal)" },
1406
+ ...props
1407
+ }
1408
+ ),
1409
+ blockquote: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("blockquote", { className: cn("md-blockquote", className), ...props }),
1410
+ hr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("hr", { className: cn("my-6 h-px border-0 bg-current opacity-10", className), ...props }),
1411
+ table: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "md-table-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("table", { className: cn("md-table", className), ...props }) }),
1412
+ thead: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("thead", { ...props }),
1413
+ tbody: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("tbody", { ...props }),
1414
+ tr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("tr", { ...props }),
1415
+ th: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("th", { ...props }),
1416
+ td: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("td", { ...props }),
1417
+ pre: MarkdownPre,
1418
+ // React Markdown v10 no longer consistently provides the legacy `inline`
1419
+ // prop. Fenced code is handled by the custom `pre` renderer above, so a
1420
+ // standalone `code` element should always be rendered as inline code.
1421
+ code: ({ className, children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("code", { className: cn("md-inline-code", className), ...props, children })
1422
+ };
1423
+ var MarkdownContent = ({ children, className }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: cn("md-content break-words text-inherit", className), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1424
+ import_react_markdown.default,
1425
+ {
1426
+ remarkPlugins: markdownPlugins.remark,
1427
+ rehypePlugins: markdownPlugins.rehype,
1428
+ components: markdownComponents,
1429
+ children
1430
+ }
1431
+ ) });
1432
+
1433
+ // src/components/Message/message.thinking.tsx
1434
+ var import_lucide_react5 = require("lucide-react");
1435
+ var import_react13 = require("react");
1436
+
1437
+ // src/components/Message/message.loading.tsx
1438
+ var import_react12 = require("react");
1439
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1440
+ var useElapsedTime = (active) => {
1441
+ const startedAtRef = (0, import_react12.useRef)(0);
1442
+ const [elapsed, setElapsed] = (0, import_react12.useState)(0);
1443
+ (0, import_react12.useEffect)(() => {
1444
+ if (!active) {
1445
+ return;
1446
+ }
1447
+ startedAtRef.current = Date.now();
1448
+ setElapsed(0);
1449
+ const timer = window.setInterval(() => {
1450
+ setElapsed(Date.now() - startedAtRef.current);
1451
+ }, 100);
1452
+ return () => window.clearInterval(timer);
1453
+ }, [active]);
1454
+ return elapsed;
1455
+ };
1456
+ var formatElapsedWords = (milliseconds) => {
1457
+ const seconds = Math.max(0, Math.floor(milliseconds / 1e3));
1458
+ if (seconds < 60) {
1459
+ return `${seconds} ${seconds === 1 ? "second" : "seconds"}`;
1460
+ }
1461
+ const minutes = Math.floor(seconds / 60);
1462
+ const remainder = seconds % 60;
1463
+ const minuteLabel = `${minutes} ${minutes === 1 ? "minute" : "minutes"}`;
1464
+ return remainder > 0 ? `${minuteLabel} ${remainder} ${remainder === 1 ? "second" : "seconds"}` : minuteLabel;
1465
+ };
1466
+
1467
+ // src/components/Message/message.thinking.tsx
1468
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1469
+ var ThinkingBlock = ({ isComplete, elapsedMs, children }) => {
1470
+ const [isOpen, setIsOpen] = (0, import_react13.useState)(true);
1471
+ const measuredElapsed = useElapsedTime(!isComplete);
1472
+ const elapsed = elapsedMs != null ? elapsedMs : measuredElapsed;
1473
+ (0, import_react13.useEffect)(() => {
1474
+ if (!isComplete) {
1475
+ setIsOpen(true);
1476
+ }
1477
+ }, [isComplete]);
1478
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1479
+ "details",
1480
+ {
1481
+ className: cn(
1482
+ "md-thinking",
1483
+ isComplete ? "md-thinking-complete" : "md-thinking-pending"
1484
+ ),
1485
+ open: isOpen,
1486
+ onToggle: (event) => setIsOpen(event.currentTarget.open),
1487
+ children: [
1488
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("summary", { children: [
1489
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.Sparkles, { className: "md-thinking-sparkle", "aria-hidden": "true" }),
1490
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1491
+ TextSwap,
1492
+ {
1493
+ className: "md-thinking-label",
1494
+ text: isComplete ? `Thought for ${formatElapsedWords(elapsed)}` : "Thinking"
1495
+ }
1496
+ ),
1497
+ isComplete && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.ChevronDown, { className: "md-thinking-chevron", "aria-hidden": "true" })
1498
+ ] }),
1499
+ children
1500
+ ]
1501
+ }
1502
+ );
1503
+ };
1504
+
1505
+ // src/components/Message/message.content.tsx
1506
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1507
+ var isPropsRecord = (value) => !!value && typeof value === "object" && !Array.isArray(value);
1508
+ var formatJson = (value) => {
1509
+ if (typeof value === "string") {
1510
+ return value;
1511
+ }
1512
+ try {
1513
+ return JSON.stringify(value, null, 2);
1514
+ } catch {
1515
+ return String(value);
1516
+ }
1517
+ };
1518
+ var toolDetail = (part) => {
1519
+ var _a, _b, _c, _d, _e, _f;
1520
+ const source = (_a = part.output) != null ? _a : part.input;
1521
+ if (!isPropsRecord(source)) {
1522
+ return null;
1523
+ }
1524
+ const value = (_f = (_e = (_d = (_c = (_b = source.path) != null ? _b : source.file) != null ? _c : source.filename) != null ? _d : source.query) != null ? _e : source.command) != null ? _f : source.url;
1525
+ return typeof value === "string" && value.trim() ? value : null;
1526
+ };
1527
+ var toolStateLabel = (state) => {
1528
+ switch (state) {
1529
+ case "input-streaming":
1530
+ return "Preparing";
1531
+ case "input-available":
1532
+ return "Ready";
1533
+ case "approval-requested":
1534
+ return "Needs approval";
1535
+ case "approval-responded":
1536
+ return "Approval sent";
1537
+ case "output-available":
1538
+ return "Done";
1539
+ case "output-error":
1540
+ return "Error";
1541
+ case "output-denied":
1542
+ return "Denied";
1543
+ default:
1544
+ return state;
1545
+ }
1546
+ };
1547
+ var ReasoningBlock = ({ part }) => {
1548
+ const isComplete = part.state !== "streaming";
1549
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ThinkingBlock, { isComplete, children: !!part.text.trim() && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "md-thinking-body", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MarkdownContent, { children: part.text }) }) });
1550
+ };
1551
+ var ToolStatusIcon = ({
1552
+ isPending,
1553
+ isDone
1554
+ }) => {
1555
+ const pathRef = (0, import_react14.useRef)(null);
1556
+ const [sawPending, setSawPending] = (0, import_react14.useState)(isPending);
1557
+ const iconState = isPending ? "a" : "b";
1558
+ const playCheck = Boolean(sawPending && isDone);
1559
+ const checkState = playCheck ? "in" : "out";
1560
+ if (isPending && !sawPending) {
1561
+ setSawPending(true);
1562
+ }
1563
+ (0, import_react14.useLayoutEffect)(() => {
1564
+ if (pathRef.current) {
1565
+ calibrateCheckPath(pathRef.current);
1566
+ }
1567
+ }, [playCheck]);
1568
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-tool-dot", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: motion.iconSwap, "data-state": iconState, children: [
1569
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: motion.icon, "data-icon": "a", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-tool-spinner" }) }),
1570
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: motion.icon, "data-icon": "b", children: isDone ? playCheck ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: motion.successCheck, "data-state": checkState, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { viewBox: "0 0 12 12", width: "10", height: "10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1571
+ "path",
1572
+ {
1573
+ ref: pathRef,
1574
+ d: "M2.5 6.5 5 9l4.5-6",
1575
+ stroke: "currentColor",
1576
+ strokeWidth: "1.6",
1577
+ strokeLinecap: "round",
1578
+ strokeLinejoin: "round"
1579
+ }
1580
+ ) }) }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { viewBox: "0 0 12 12", width: "10", height: "10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1581
+ "path",
1582
+ {
1583
+ d: "M2.5 6.5 5 9l4.5-6",
1584
+ stroke: "currentColor",
1585
+ strokeWidth: "1.6",
1586
+ strokeLinecap: "round",
1587
+ strokeLinejoin: "round"
1588
+ }
1589
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { viewBox: "0 0 12 12", width: "10", height: "10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1590
+ "path",
1591
+ {
1592
+ d: "M3.2 3.2 8.8 8.8M8.8 3.2 3.2 8.8",
1593
+ stroke: "currentColor",
1594
+ strokeWidth: "1.6",
1595
+ strokeLinecap: "round"
1596
+ }
1597
+ ) }) })
1598
+ ] }) });
1599
+ };
1600
+ var ToolBlock = ({ part }) => {
1601
+ var _a;
1602
+ const wrapRef = (0, import_react14.useRef)(null);
1603
+ const isPending = part.state === "input-streaming" || part.state === "input-available" || part.state === "approval-requested";
1604
+ const isError = part.state === "output-error" || part.state === "output-denied";
1605
+ const isDone = !isPending && !isError;
1606
+ const detail = toolDetail(part);
1607
+ (0, import_react14.useEffect)(() => {
1608
+ if (!isError || !wrapRef.current) {
1609
+ return;
1610
+ }
1611
+ triggerErrorShake(wrapRef.current, { revert: false });
1612
+ }, [isError]);
1613
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1614
+ "details",
1615
+ {
1616
+ ref: wrapRef,
1617
+ className: cn(
1618
+ "agent-tool",
1619
+ motion.inputWrap,
1620
+ isPending ? "agent-tool-pending" : isError ? "agent-tool-error" : "agent-tool-complete"
1621
+ ),
1622
+ open: isPending || isError,
1623
+ children: [
1624
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("summary", { className: cn(motion.input, isError && motion.isError), children: [
1625
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react6.ChevronDown, { className: "agent-tool-chevron", "aria-hidden": "true" }),
1626
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ToolStatusIcon, { isPending, isDone }),
1627
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-tool-name", children: (_a = part.title) != null ? _a : part.toolName }),
1628
+ detail ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-tool-chip", children: detail }) : null,
1629
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TextSwap, { className: "agent-tool-state", text: toolStateLabel(part.state) })
1630
+ ] }),
1631
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "agent-tool-body", children: [
1632
+ part.input !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "agent-tool-section", children: [
1633
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "agent-tool-section-label", children: "Input" }),
1634
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("pre", { className: "agent-tool-code", children: formatJson(part.input) })
1635
+ ] }),
1636
+ part.output !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "agent-tool-section", children: [
1637
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "agent-tool-section-label", children: "Output" }),
1638
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("pre", { className: "agent-tool-code", children: formatJson(part.output) })
1639
+ ] }),
1640
+ part.errorText && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "agent-tool-section", children: [
1641
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "agent-tool-section-label", children: "Error" }),
1642
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("pre", { className: "agent-tool-code agent-tool-error", children: part.errorText })
1643
+ ] })
1644
+ ] })
1645
+ ]
1646
+ }
1647
+ );
1648
+ };
1649
+ var SourceUrlBlock = ({ part }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("a", { className: "agent-source", href: part.url, target: "_blank", rel: "noreferrer", children: [
1650
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-source-label", children: "Source" }),
1651
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-source-title", children: part.title || part.url })
1652
+ ] });
1653
+ var SourceDocumentBlock = ({ part }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "agent-source agent-source-document", children: [
1654
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-source-label", children: "Document" }),
1655
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-source-title", children: part.title }),
1656
+ part.filename && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-source-meta", children: part.filename })
1657
+ ] });
1658
+ var FileBlock = ({ part }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ArtifactWidget, { artifact: {
1659
+ id: part.url,
1660
+ filename: part.filename || (part.mediaType.startsWith("image/") ? "Generated image" : "Generated file"),
1661
+ mediaType: part.mediaType,
1662
+ url: part.url,
1663
+ status: "ready"
1664
+ } });
1665
+ var AgentEventBlock = ({ part }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("details", { className: "agent-tool agent-event", children: [
1666
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("summary", { children: [
1667
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-event-marker", "aria-hidden": "true" }),
1668
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "agent-tool-name", children: [
1669
+ "data.",
1670
+ part.name
1671
+ ] })
1672
+ ] }),
1673
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "agent-tool-body", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("pre", { className: "agent-tool-code", children: formatJson(part.data) }) })
1674
+ ] });
1675
+ var TextWithLegacyThinking = ({ text, isUser }) => {
1676
+ var _a;
1677
+ const userReferenceMessage = isUser ? parseUserReferenceMessage(text) : null;
1678
+ const content = (_a = userReferenceMessage == null ? void 0 : userReferenceMessage.message) != null ? _a : text;
1679
+ const segments = splitThinkingSegments(content);
1680
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
1681
+ userReferenceMessage && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "chat-user-reference", children: userReferenceMessage.references.map((reference, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1682
+ "div",
1683
+ {
1684
+ className: "chat-user-reference-item",
1685
+ children: [
1686
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "chat-reference-label", children: [
1687
+ "Reference ",
1688
+ index + 1
1689
+ ] }),
1690
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "chat-reference-text", children: reference })
1691
+ ]
1692
+ },
1693
+ `${index}-${reference.slice(0, 16)}`
1694
+ )) }),
1695
+ segments.map((segment, index) => {
1696
+ var _a2;
1697
+ if (!segment.content.trim() && segment.type !== "thinking") {
1698
+ return null;
1699
+ }
1700
+ if (segment.type === "thinking" && !isUser) {
1701
+ const isComplete = (_a2 = segment.isComplete) != null ? _a2 : true;
1702
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ThinkingBlock, { isComplete, children: !!segment.content.trim() && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "md-thinking-body", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MarkdownContent, { children: segment.content }) }) }, `thinking-${index}`);
1703
+ }
1704
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MarkdownContent, { children: segment.content }, `md-${index}`);
1705
+ })
1706
+ ] });
1707
+ };
1708
+ var asWidgetFromTool = (part) => {
1709
+ const source = part.state === "output-available" && part.output !== void 0 ? part.output : part.input;
1710
+ if (!isPropsRecord(source)) {
1711
+ return null;
1712
+ }
1713
+ return {
1714
+ type: "widget",
1715
+ name: part.toolName,
1716
+ id: part.toolCallId,
1717
+ props: source,
1718
+ interactive: part.toolName === "question" || source.interactive === true
1719
+ };
1720
+ };
1721
+ var asWidgetFromData = (part) => ({
1722
+ type: "widget",
1723
+ name: part.name,
1724
+ id: part.id,
1725
+ props: isPropsRecord(part.data) ? part.data : { value: part.data },
1726
+ interactive: isPropsRecord(part.data) ? part.data.interactive === true : false
1727
+ });
1728
+ var PartView = ({ part, index, isUser }) => {
1729
+ const { widgets } = useWidgets();
1730
+ if (part.type === "widget") {
1731
+ return isUser ? null : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(WidgetRenderer, { part }, `widget-${part.id || index}`);
1732
+ }
1733
+ if (part.type === "tool" && !isUser) {
1734
+ const entry = widgets[part.toolName];
1735
+ const isCustom = entry && entry !== prebuiltWidgets[part.toolName];
1736
+ const widgetPart = isCustom ? asWidgetFromTool(part) : computeToolWidget(part);
1737
+ if (widgetPart) {
1738
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1739
+ WidgetRenderer,
1740
+ {
1741
+ part: widgetPart,
1742
+ pending: part.state === "input-streaming"
1743
+ },
1744
+ `tool-widget-${part.toolCallId || index}`
1745
+ );
1746
+ }
1747
+ }
1748
+ if (part.type === "data" && !isUser && widgets[part.name]) {
1749
+ const builtin = widgets[part.name] === prebuiltWidgets[part.name];
1750
+ if (builtin && (part.name === "artifact" && !(0, import_protocol2.parseArtifact)(part.data) || part.name === "subagent" && !(0, import_protocol2.parseSubagent)(part.data))) return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AgentEventBlock, { part });
1751
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1752
+ WidgetRenderer,
1753
+ {
1754
+ part: asWidgetFromData(part)
1755
+ },
1756
+ `data-widget-${part.name}-${part.id || index}`
1757
+ );
1758
+ }
1759
+ switch (part.type) {
1760
+ case "text":
1761
+ if (!isUser && part.state === "streaming" && part.text.trim().length === 0) {
1762
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TextSkeleton, {}, `text-${index}`);
1763
+ }
1764
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TextWithLegacyThinking, { text: part.text, isUser }, `text-${index}`);
1765
+ case "reasoning":
1766
+ return isUser ? null : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReasoningBlock, { part }, `reasoning-${index}`);
1767
+ case "tool":
1768
+ return isUser ? null : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ToolBlock, { part }, `tool-${part.toolCallId || index}`);
1769
+ case "source-url":
1770
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SourceUrlBlock, { part }, `source-url-${part.sourceId || index}`);
1771
+ case "source-document":
1772
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SourceDocumentBlock, { part }, `source-doc-${part.sourceId || index}`);
1773
+ case "file":
1774
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(FileBlock, { part }, `file-${index}`);
1775
+ case "data":
1776
+ if (part.name === "usage" || part.name === "context" || part.name === "context-warning") {
1777
+ return null;
1778
+ }
1779
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AgentEventBlock, { part }, `data-${part.name}-${part.id || index}`);
1780
+ case "unknown":
1781
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("details", { className: "agent-tool agent-event", children: [
1782
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("summary", { children: [
1783
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-event-marker", "aria-hidden": "true" }),
1784
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "agent-tool-name", children: part.rawType })
1785
+ ] }),
1786
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "agent-tool-body", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("pre", { className: "agent-tool-code", children: formatJson(part.raw) }) })
1787
+ ] }, `unknown-${index}`);
1788
+ default:
1789
+ return null;
1790
+ }
1791
+ };
1792
+ var MessageContent = ({ parts, isUser = false }) => {
1793
+ const agentParts = (0, import_protocol2.normalizeAgentParts)(parts);
1794
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1795
+ "div",
1796
+ {
1797
+ className: cn(
1798
+ "chat-message-content break-words",
1799
+ isUser ? "md-content-user" : "md-content-assistant"
1800
+ ),
1801
+ children: agentParts.map((part, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PartView, { part, index, isUser }, `${part.type}-${index}`))
1802
+ }
1803
+ );
1804
+ };
1805
+
1806
+ // src/widgets/subagent.tsx
1807
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1808
+ var Depth = (0, import_react15.createContext)(0);
1809
+ var labels = { queued: "Queued", running: "Working", completed: "Completed", failed: "Failed", cancelled: "Cancelled" };
1810
+ function SubagentWidget({ subagent, className = "" }) {
1811
+ const depth = (0, import_react15.useContext)(Depth);
1812
+ const { title, task, state, summary, progress, messages = [], artifacts = [], error } = subagent;
1813
+ const Icon = state === "completed" ? import_lucide_react7.CircleCheck : state === "failed" ? import_lucide_react7.CircleX : state === "running" ? import_lucide_react7.LoaderCircle : import_lucide_react7.Bot;
1814
+ const canInspect = depth < 3;
1815
+ const transcript = messages.filter((message) => message.role !== "system");
1816
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { className: "chat-prebuilt chat-subagent " + className, "data-state": state, "aria-label": "Subagent: " + title, children: [
1817
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "chat-subagent-heading", children: [
1818
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "chat-subagent-icon", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Icon, { size: 18, "aria-hidden": "true" }) }),
1819
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
1820
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("strong", { children: title }),
1821
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "chat-subagent-state", role: "status", children: labels[state] })
1822
+ ] }),
1823
+ canInspect ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1824
+ ResponsiveDetail,
1825
+ {
1826
+ title,
1827
+ description: task || "Subagent activity in this conversation",
1828
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { className: "chat-subagent-inspect", type: "button", "aria-label": "View activity for " + title, children: [
1829
+ "View activity",
1830
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react7.ArrowUpRight, { size: 14, "aria-hidden": "true" })
1831
+ ] }),
1832
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Depth.Provider, { value: depth + 1, children: [
1833
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "chat-subagent-overview", children: [
1834
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "chat-subagent-state", children: labels[state] }),
1835
+ progress !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { children: [
1836
+ Math.round(progress * 100),
1837
+ "%"
1838
+ ] }) : null
1839
+ ] }),
1840
+ summary ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "chat-subagent-summary", children: summary }) : null,
1841
+ error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "chat-widget-error", role: "alert", children: error }) : null,
1842
+ transcript.length ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "chat-subagent-transcript", children: transcript.map((message) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("article", { className: "chat-subagent-message", children: [
1843
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "chat-subagent-role", children: message.role === "user" ? "Task" : title }),
1844
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(MessageContent, { parts: message.parts, isUser: message.role === "user" })
1845
+ ] }, message.id)) }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "chat-widget-empty", children: state === "queued" ? "Waiting to start." : state === "running" ? "Activity will appear as the agent works." : "No activity was recorded." }),
1846
+ artifacts.length ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "chat-subagent-artifacts", children: [
1847
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h4", { children: "Created files" }),
1848
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ArtifactsWidget, { artifacts })
1849
+ ] }) : null
1850
+ ] })
1851
+ }
1852
+ ) : null
1853
+ ] }),
1854
+ task ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "chat-subagent-task", children: task }) : null,
1855
+ summary ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "chat-subagent-summary", children: summary }) : null,
1856
+ state === "running" && progress !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("progress", { className: "chat-subagent-progress", value: progress, max: 1, "aria-label": "Progress for " + title }) : null,
1857
+ state === "failed" && error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "chat-widget-error", role: "alert", children: error }) : null
1858
+ ] });
1859
+ }
1860
+
1861
+ // src/widgets/registry.tsx
1862
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1863
+ var str = (value, fallback = "") => typeof value === "string" ? value : fallback;
1864
+ var num = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
1865
+ var common = (props) => ({
1866
+ state: props.state === "running" || props.state === "error" || props.state === "denied" || props.state === "approval" ? props.state : "complete",
1867
+ error: typeof props.error === "string" ? props.error : void 0
1868
+ });
1869
+ function Read(props) {
1870
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1871
+ ReadFileWidget,
1872
+ {
1873
+ ...common(props),
1874
+ path: str(props.path, "File"),
1875
+ content: typeof props.content === "string" ? props.content : void 0,
1876
+ startLine: num(props.startLine),
1877
+ language: str(props.language)
1878
+ }
1879
+ );
1880
+ }
1881
+ function Patch(props) {
1882
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1883
+ PatchWidget,
1884
+ {
1885
+ ...common(props),
1886
+ path: str(props.path, "File changes"),
1887
+ diff: typeof props.diff === "string" ? props.diff : void 0,
1888
+ before: typeof props.before === "string" ? props.before : void 0,
1889
+ after: typeof props.after === "string" ? props.after : void 0
1890
+ }
1891
+ );
1892
+ }
1893
+ function Search(props) {
1894
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1895
+ SearchWidget,
1896
+ {
1897
+ ...common(props),
1898
+ query: str(props.query),
1899
+ results: normalizeSearchResults(props.results),
1900
+ total: num(props.total)
1901
+ }
1902
+ );
1903
+ }
1904
+ function Question(props) {
1905
+ const options = Array.isArray(props.options) ? props.options.flatMap((item) => {
1906
+ if (typeof item === "string") return [{ label: item, value: item }];
1907
+ if (!item || typeof item !== "object" || typeof item.label !== "string" || typeof item.value !== "string")
1908
+ return [];
1909
+ return [
1910
+ {
1911
+ label: item.label,
1912
+ value: item.value,
1913
+ description: str(item.description),
1914
+ recommended: item.recommended === true
1915
+ }
1916
+ ];
1917
+ }) : [];
1918
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1919
+ QuestionWidget,
1920
+ {
1921
+ prompt: str(props.prompt, "Your answer"),
1922
+ description: str(props.description),
1923
+ options,
1924
+ multiple: props.multiple === true,
1925
+ allowCustom: props.allowCustom === true,
1926
+ disabled: !props.widget.interactive || props.widget.disabled,
1927
+ onSubmit: async (answer) => {
1928
+ const labels2 = answer.values.map(
1929
+ (value) => {
1930
+ var _a, _b;
1931
+ return (_b = (_a = options.find((option) => option.value === value)) == null ? void 0 : _a.label) != null ? _b : value;
1932
+ }
1933
+ );
1934
+ await props.widget.respond(
1935
+ answer,
1936
+ [...labels2, answer.text].filter(Boolean).join(", "),
1937
+ "answer"
1938
+ );
1939
+ }
1940
+ }
1941
+ );
1942
+ }
1943
+ function Artifact(props) {
1944
+ var _a;
1945
+ const artifact = (0, import_protocol3.parseArtifact)((_a = props.artifact) != null ? _a : props);
1946
+ return artifact ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ArtifactWidget, { artifact }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "chat-widget-empty", children: "File details are unavailable." });
1947
+ }
1948
+ function Artifacts(props) {
1949
+ const artifacts = Array.isArray(props.artifacts) ? props.artifacts.flatMap((value) => {
1950
+ const artifact = (0, import_protocol3.parseArtifact)(value);
1951
+ return artifact ? [artifact] : [];
1952
+ }) : [];
1953
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ArtifactsWidget, { artifacts });
1954
+ }
1955
+ function Subagent(props) {
1956
+ var _a;
1957
+ const subagent = (0, import_protocol3.parseSubagent)((_a = props.subagent) != null ? _a : props);
1958
+ return subagent ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SubagentWidget, { subagent }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "chat-widget-empty", children: "Agent details are unavailable." });
1959
+ }
1960
+ var prebuiltWidgets = {
1961
+ artifact: { name: "artifact", component: Artifact, shell: false },
1962
+ artifacts: { name: "artifacts", component: Artifacts, shell: false },
1963
+ subagent: { name: "subagent", component: Subagent, shell: false },
1964
+ "read-file": { name: "read-file", component: Read, shell: false },
1965
+ patch: { name: "patch", component: Patch, shell: false },
1966
+ search: { name: "search", component: Search, shell: false },
1967
+ question: { name: "question", component: Question, shell: false }
1968
+ };
1969
+
1970
+ // src/widgets/index.ts
1971
+ var import_protocol4 = require("@sarchauhan/protocol");
1972
+ // Annotate the CommonJS export names for ESM import in node:
1973
+ 0 && (module.exports = {
1974
+ ArtifactWidget,
1975
+ ArtifactsWidget,
1976
+ PatchWidget,
1977
+ QuestionWidget,
1978
+ ReadFileWidget,
1979
+ ResponsiveDetail,
1980
+ SearchWidget,
1981
+ SubagentWidget,
1982
+ computeDiff,
1983
+ computeTextDiff,
1984
+ computeToolState,
1985
+ computeToolWidget,
1986
+ createArtifactData,
1987
+ createSubagentData,
1988
+ formatArtifactSize,
1989
+ normalizeSearchResults,
1990
+ parseArtifact,
1991
+ parseSubagent,
1992
+ prebuiltWidgets,
1993
+ safeArtifactUrl,
1994
+ safeResultUrl
1995
+ });
1996
+ //# sourceMappingURL=widgets.js.map