@pgege/kaboo-react 0.1.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.
@@ -0,0 +1,1248 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/copilotkit.ts
21
+ var copilotkit_exports = {};
22
+ __export(copilotkit_exports, {
23
+ KabooAskUser: () => KabooAskUser,
24
+ KabooAssistantMessage: () => KabooAssistantMessage,
25
+ KabooInlineCards: () => KabooInlineCards,
26
+ KabooInterruptHandler: () => KabooInterruptHandler,
27
+ KabooMessageView: () => KabooMessageView,
28
+ KabooToolRender: () => KabooToolRender
29
+ });
30
+ module.exports = __toCommonJS(copilotkit_exports);
31
+
32
+ // src/integrations/KabooInlineCards.tsx
33
+ var import_v23 = require("@copilotkit/react-core/v2");
34
+
35
+ // src/hooks/useActivity.ts
36
+ var import_react2 = require("react");
37
+
38
+ // src/context/ActivityProvider.tsx
39
+ var import_react = require("react");
40
+ var import_v2 = require("@copilotkit/react-core/v2");
41
+ var import_jsx_runtime = require("react/jsx-runtime");
42
+ var EMPTY = { groups: {} };
43
+ var ActivityContext = (0, import_react.createContext)(EMPTY);
44
+ var StructuredRenderersContext = (0, import_react.createContext)({});
45
+
46
+ // src/hooks/useActivity.ts
47
+ function useActivity() {
48
+ return (0, import_react2.useContext)(ActivityContext);
49
+ }
50
+
51
+ // src/components/AgentCard.tsx
52
+ var import_react9 = require("react");
53
+
54
+ // src/formatters/output.ts
55
+ function formatToolResult(raw) {
56
+ try {
57
+ const parsed = JSON.parse(raw);
58
+ if (parsed.rows && Array.isArray(parsed.rows) && parsed.rows.length > 0) {
59
+ return { rows: parsed.rows, text: "" };
60
+ }
61
+ if (Array.isArray(parsed) && parsed.length > 0 && typeof parsed[0] === "object") {
62
+ return { rows: parsed, text: "" };
63
+ }
64
+ if (typeof parsed === "object" && parsed !== null) {
65
+ const entries = Object.entries(parsed).filter(([, v]) => v != null).map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`);
66
+ return { rows: null, text: entries.join("\n") };
67
+ }
68
+ return { rows: null, text: String(parsed) };
69
+ } catch {
70
+ return { rows: null, text: raw };
71
+ }
72
+ }
73
+ function unwrapJson(raw) {
74
+ let value = raw;
75
+ for (let i = 0; i < 2 && typeof value === "string"; i++) {
76
+ const trimmed = value.trim();
77
+ if (trimmed === "") return value;
78
+ try {
79
+ value = JSON.parse(trimmed);
80
+ } catch {
81
+ break;
82
+ }
83
+ }
84
+ return value;
85
+ }
86
+ function statusIsCancelled(status) {
87
+ if (typeof status !== "string") return false;
88
+ const s = status.toLowerCase();
89
+ return s === "cancelled" || s === "canceled" || s === "rejected" || s === "declined";
90
+ }
91
+ function statusIsControl(status) {
92
+ if (typeof status !== "string") return false;
93
+ const s = status.toLowerCase();
94
+ return statusIsCancelled(status) || s === "approved" || s === "accepted";
95
+ }
96
+ function isCancelledResult(raw) {
97
+ if (raw == null) return false;
98
+ const text = typeof raw === "string" ? raw : JSON.stringify(raw);
99
+ if (/user rejected this action/i.test(text)) return true;
100
+ if (/user declined to answer/i.test(text)) return true;
101
+ const value = unwrapJson(text);
102
+ if (value && typeof value === "object" && !Array.isArray(value)) {
103
+ return statusIsCancelled(value.status);
104
+ }
105
+ return false;
106
+ }
107
+ function isControlOnlyStatus(raw) {
108
+ if (raw == null) return false;
109
+ const value = unwrapJson(typeof raw === "string" ? raw : JSON.stringify(raw));
110
+ if (value && typeof value === "object" && !Array.isArray(value)) {
111
+ const keys = Object.keys(value);
112
+ return keys.length === 1 && keys[0] === "status" && statusIsControl(value.status);
113
+ }
114
+ return false;
115
+ }
116
+ function normalizeResult(result) {
117
+ if (!result) return null;
118
+ let text = typeof result === "string" ? result : JSON.stringify(result, null, 2);
119
+ if (text.startsWith('"') && text.endsWith('"')) {
120
+ try {
121
+ text = JSON.parse(text);
122
+ } catch {
123
+ }
124
+ }
125
+ text = text.replace(/\\n/g, "\n");
126
+ return text || null;
127
+ }
128
+
129
+ // src/components/MarkdownContent.tsx
130
+ var import_jsx_runtime2 = require("react/jsx-runtime");
131
+ function MarkdownContent({ text }) {
132
+ const lines = text.split("\n");
133
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "kaboo-md", children: lines.map((line, i) => {
134
+ if (line.startsWith("# ") && !line.startsWith("## ")) {
135
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { className: "kaboo-md-h2", children: line.slice(2) }, i);
136
+ }
137
+ if (line.startsWith("## ")) {
138
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "kaboo-md-h3", children: line.slice(3) }, i);
139
+ }
140
+ if (line.startsWith("### ")) {
141
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h4", { className: "kaboo-md-h4", children: line.slice(4) }, i);
142
+ }
143
+ if (line.startsWith("- ") || line.startsWith("* ")) {
144
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { className: "kaboo-md-li", children: renderInline(line.slice(2)) }, i);
145
+ }
146
+ if (line.trim() === "") {
147
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "kaboo-md-spacer" }, i);
148
+ }
149
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "kaboo-md-p", children: renderInline(line) }, i);
150
+ }) });
151
+ }
152
+ function renderInline(text) {
153
+ const parts = [];
154
+ let remaining = text;
155
+ let key = 0;
156
+ while (remaining.length > 0) {
157
+ const boldMatch = remaining.match(/\*\*(.+?)\*\*/);
158
+ if (boldMatch && boldMatch.index !== void 0) {
159
+ if (boldMatch.index > 0) {
160
+ parts.push(remaining.slice(0, boldMatch.index));
161
+ }
162
+ parts.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: boldMatch[1] }, key++));
163
+ remaining = remaining.slice(boldMatch.index + boldMatch[0].length);
164
+ continue;
165
+ }
166
+ parts.push(remaining);
167
+ break;
168
+ }
169
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: parts });
170
+ }
171
+
172
+ // src/components/Timeline.tsx
173
+ var import_react6 = require("react");
174
+
175
+ // src/components/ToolRow.tsx
176
+ var import_react3 = require("react");
177
+
178
+ // src/formatters/input.ts
179
+ function formatToolInput(input) {
180
+ if (input == null) return { summary: "", detail: null };
181
+ if (typeof input === "string") return { summary: input, detail: null };
182
+ const obj = input;
183
+ if (obj.query && typeof obj.query === "string") {
184
+ return { summary: String(obj.query).trim(), detail: null };
185
+ }
186
+ if (obj.table_name && typeof obj.table_name === "string") {
187
+ return { summary: obj.table_name, detail: null };
188
+ }
189
+ if (obj.url && typeof obj.url === "string") {
190
+ return { summary: obj.url, detail: null };
191
+ }
192
+ const keys = Object.keys(obj);
193
+ if (keys.length === 1) {
194
+ const val = obj[keys[0]];
195
+ return { summary: typeof val === "string" ? val : JSON.stringify(val), detail: null };
196
+ }
197
+ const parts = keys.filter((k) => obj[k] != null && obj[k] !== "").map((k) => {
198
+ const v = obj[k];
199
+ return `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`;
200
+ });
201
+ return { summary: parts.join(", "), detail: null };
202
+ }
203
+
204
+ // src/components/MiniTable.tsx
205
+ var import_jsx_runtime3 = require("react/jsx-runtime");
206
+ function MiniTable({ rows, maxRows = 8 }) {
207
+ if (rows.length === 0) return null;
208
+ const cols = Object.keys(rows[0]);
209
+ const display = rows.slice(0, maxRows);
210
+ const remaining = rows.length - maxRows;
211
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { overflowX: "auto" }, children: [
212
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("table", { className: "kaboo-mini-table", children: [
213
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tr", { children: cols.map((c) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { children: c.replace(/_/g, " ") }, c)) }) }),
214
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tbody", { children: display.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tr", { children: cols.map((c) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { children: String(row[c] ?? "") }, c)) }, i)) })
215
+ ] }),
216
+ remaining > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "kaboo-mini-table-overflow", children: [
217
+ "+",
218
+ remaining,
219
+ " more row",
220
+ remaining !== 1 ? "s" : ""
221
+ ] })
222
+ ] });
223
+ }
224
+
225
+ // src/components/ToolRow.tsx
226
+ var import_jsx_runtime4 = require("react/jsx-runtime");
227
+ function ToolRow({ tool }) {
228
+ const [open, setOpen] = (0, import_react3.useState)(false);
229
+ const cancelled = tool.status === "cancelled" || isCancelledResult(tool.toolResult);
230
+ const isDone = tool.status !== "running";
231
+ const label = tool.toolLabel || tool.toolName;
232
+ const { summary: inputSummary } = formatToolInput(tool.toolInput);
233
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "kaboo-tool-row", children: [
234
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "kaboo-tool-row-header", onClick: () => setOpen(!open), children: [
235
+ tool.status === "running" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: 10, height: 10, viewBox: "0 0 16 16", className: "kaboo-icon-shrink", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
236
+ "circle",
237
+ {
238
+ cx: "8",
239
+ cy: "8",
240
+ r: "5",
241
+ fill: "none",
242
+ className: "kaboo-tool-spinner",
243
+ strokeWidth: "2",
244
+ strokeDasharray: "22",
245
+ strokeDashoffset: "6",
246
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
247
+ "animateTransform",
248
+ {
249
+ attributeName: "transform",
250
+ type: "rotate",
251
+ from: "0 8 8",
252
+ to: "360 8 8",
253
+ dur: "0.8s",
254
+ repeatCount: "indefinite"
255
+ }
256
+ )
257
+ }
258
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: 10, height: 10, viewBox: "0 0 10 10", className: "kaboo-icon-shrink", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
259
+ "circle",
260
+ {
261
+ cx: "5",
262
+ cy: "5",
263
+ r: "3",
264
+ className: cancelled ? "kaboo-tool-dot-cancelled" : tool.status === "error" ? "kaboo-tool-dot-error" : "kaboo-tool-dot-success"
265
+ }
266
+ ) }),
267
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "kaboo-tool-row-label", children: label }),
268
+ isDone && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "kaboo-tool-row-status", children: cancelled ? "cancelled" : tool.status === "error" ? "error" : "done" }),
269
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
270
+ "svg",
271
+ {
272
+ width: 14,
273
+ height: 14,
274
+ viewBox: "0 0 16 16",
275
+ className: `kaboo-chevron ${open ? "kaboo-chevron-open" : ""}`,
276
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4 6l4 4 4-4", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
277
+ }
278
+ )
279
+ ] }),
280
+ !open && inputSummary && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "kaboo-tool-row-summary", children: inputSummary.length > 80 ? inputSummary.slice(0, 80) + "..." : inputSummary }),
281
+ open && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "kaboo-tool-row-detail", children: [
282
+ inputSummary && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "kaboo-tool-input", children: inputSummary }),
283
+ tool.toolResult && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToolResultBlock, { raw: tool.toolResult, cancelled })
284
+ ] })
285
+ ] });
286
+ }
287
+ function ToolResultBlock({ raw, cancelled }) {
288
+ if (cancelled) {
289
+ const { text: text2 } = formatToolResult(raw);
290
+ const message = /user (rejected|declined)/i.test(text2) ? text2 : "Declined by user.";
291
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "kaboo-tool-result kaboo-tool-result-cancelled", children: message });
292
+ }
293
+ const { rows, text } = formatToolResult(raw);
294
+ if (rows) {
295
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "kaboo-tool-result kaboo-tool-result-table", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MiniTable, { rows }) });
296
+ }
297
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "kaboo-tool-result", children: text });
298
+ }
299
+
300
+ // src/components/AskUserSummary.tsx
301
+ var import_jsx_runtime5 = require("react/jsx-runtime");
302
+ function formatAnswer(value) {
303
+ if (value == null) return "";
304
+ if (Array.isArray(value)) return value.map((v) => String(v)).join(", ");
305
+ if (typeof value === "object") return JSON.stringify(value);
306
+ return String(value);
307
+ }
308
+ function AskUserSummary({
309
+ questions,
310
+ answers,
311
+ declined = false
312
+ }) {
313
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "kaboo-askuser", children: questions.map((q, idx) => {
314
+ const answer = answers[q.question];
315
+ const hasAnswer = answer != null && formatAnswer(answer) !== "";
316
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "kaboo-askuser-qa", children: [
317
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "kaboo-askuser-question", children: q.question }),
318
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
319
+ "div",
320
+ {
321
+ className: `kaboo-askuser-answer ${hasAnswer ? "" : declined ? "kaboo-askuser-answer-declined" : "kaboo-askuser-answer-empty"}`,
322
+ children: hasAnswer ? formatAnswer(answer) : declined ? "Declined by user" : "No answer"
323
+ }
324
+ )
325
+ ] }, idx);
326
+ }) });
327
+ }
328
+
329
+ // src/components/InterruptRenderer.tsx
330
+ var import_react4 = require("react");
331
+ var import_jsx_runtime6 = require("react/jsx-runtime");
332
+ function ApprovalVariant({ reason, onResolve, onCancel }) {
333
+ const [responded, setResponded] = (0, import_react4.useState)(false);
334
+ if (reason.type !== "approval") return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, {});
335
+ if (responded) {
336
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "kaboo-interrupt-responded", children: "Response submitted" });
337
+ }
338
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "kaboo-interrupt kaboo-interrupt-approval", children: [
339
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "kaboo-interrupt-header", children: [
340
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: 16, height: 16, viewBox: "0 0 16 16", className: "kaboo-interrupt-icon", children: [
341
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "8", cy: "8", r: "7", fill: "none", stroke: "currentColor", strokeWidth: "1.5" }),
342
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M8 4.5v4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }),
343
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "8", cy: "11", r: "0.75", fill: "currentColor" })
344
+ ] }),
345
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "kaboo-interrupt-message", children: reason.message })
346
+ ] }),
347
+ reason.tool_input != null && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("details", { className: "kaboo-interrupt-details", children: [
348
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("summary", { children: "View input" }),
349
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { className: "kaboo-interrupt-pre", children: JSON.stringify(reason.tool_input, null, 2) })
350
+ ] }),
351
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "kaboo-interrupt-actions", children: [
352
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
353
+ "button",
354
+ {
355
+ className: "kaboo-interrupt-btn kaboo-interrupt-btn-approve",
356
+ onClick: () => {
357
+ setResponded(true);
358
+ onResolve({ status: "approved" });
359
+ },
360
+ children: "Approve"
361
+ }
362
+ ),
363
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
364
+ "button",
365
+ {
366
+ className: "kaboo-interrupt-btn kaboo-interrupt-btn-reject",
367
+ onClick: () => {
368
+ setResponded(true);
369
+ onCancel();
370
+ },
371
+ children: "Reject"
372
+ }
373
+ )
374
+ ] })
375
+ ] });
376
+ }
377
+ function withoutOther(options) {
378
+ return (options ?? []).filter((o) => o.trim().toLowerCase() !== "other");
379
+ }
380
+ function buildAnswerPayload(questions, answers) {
381
+ const out = {};
382
+ questions.forEach((q, idx) => {
383
+ out[q.question] = answers[String(idx)] ?? "";
384
+ });
385
+ return out;
386
+ }
387
+ function RadioInput({
388
+ question,
389
+ value,
390
+ onChange
391
+ }) {
392
+ const [otherText, setOtherText] = (0, import_react4.useState)("");
393
+ const [isOther, setIsOther] = (0, import_react4.useState)(false);
394
+ const options = withoutOther(question.options);
395
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "kaboo-interrupt-radio-group", children: [
396
+ options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: `kaboo-interrupt-option ${value === opt && !isOther ? "kaboo-interrupt-option-selected" : ""}`, children: [
397
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
398
+ "input",
399
+ {
400
+ type: "radio",
401
+ name: question.question,
402
+ checked: value === opt && !isOther,
403
+ onChange: () => {
404
+ setIsOther(false);
405
+ onChange(opt);
406
+ },
407
+ className: "kaboo-interrupt-radio"
408
+ }
409
+ ),
410
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: opt })
411
+ ] }, opt)),
412
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `kaboo-interrupt-option kaboo-interrupt-option-other ${isOther ? "kaboo-interrupt-option-selected" : ""}`, children: [
413
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
414
+ "input",
415
+ {
416
+ type: "radio",
417
+ name: question.question,
418
+ checked: isOther,
419
+ onChange: () => {
420
+ setIsOther(true);
421
+ onChange(otherText);
422
+ },
423
+ className: "kaboo-interrupt-radio"
424
+ }
425
+ ),
426
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
427
+ "input",
428
+ {
429
+ type: "text",
430
+ className: "kaboo-interrupt-text-input kaboo-interrupt-other-input",
431
+ placeholder: "Other (type your own answer)\u2026",
432
+ value: otherText,
433
+ onChange: (e) => {
434
+ setOtherText(e.target.value);
435
+ setIsOther(true);
436
+ onChange(e.target.value);
437
+ },
438
+ onFocus: () => {
439
+ setIsOther(true);
440
+ onChange(otherText);
441
+ }
442
+ }
443
+ )
444
+ ] })
445
+ ] });
446
+ }
447
+ function CheckboxInput({
448
+ question,
449
+ value,
450
+ onChange
451
+ }) {
452
+ const [otherText, setOtherText] = (0, import_react4.useState)("");
453
+ const options = withoutOther(question.options);
454
+ const toggle = (opt) => {
455
+ const next = value.includes(opt) ? value.filter((v) => v !== opt) : [...value, opt];
456
+ onChange(next);
457
+ };
458
+ const otherSelected = otherText !== "" && value.includes(otherText);
459
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "kaboo-interrupt-checkbox-group", children: [
460
+ options.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: `kaboo-interrupt-option ${value.includes(opt) ? "kaboo-interrupt-option-selected" : ""}`, children: [
461
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
462
+ "input",
463
+ {
464
+ type: "checkbox",
465
+ checked: value.includes(opt),
466
+ onChange: () => toggle(opt),
467
+ className: "kaboo-interrupt-checkbox"
468
+ }
469
+ ),
470
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: opt })
471
+ ] }, opt)),
472
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `kaboo-interrupt-option kaboo-interrupt-option-other ${otherSelected ? "kaboo-interrupt-option-selected" : ""}`, children: [
473
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
474
+ "input",
475
+ {
476
+ type: "checkbox",
477
+ checked: otherSelected,
478
+ onChange: () => {
479
+ if (otherSelected) onChange(value.filter((v) => v !== otherText));
480
+ else if (otherText) onChange([...value, otherText]);
481
+ },
482
+ className: "kaboo-interrupt-checkbox"
483
+ }
484
+ ),
485
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
486
+ "input",
487
+ {
488
+ type: "text",
489
+ className: "kaboo-interrupt-text-input kaboo-interrupt-other-input",
490
+ placeholder: "Other (type your own answer)\u2026",
491
+ value: otherText,
492
+ onChange: (e) => {
493
+ const prev = otherText;
494
+ const nextText = e.target.value;
495
+ setOtherText(nextText);
496
+ const filtered = value.filter((v) => v !== prev);
497
+ onChange(nextText ? [...filtered, nextText] : filtered);
498
+ }
499
+ }
500
+ )
501
+ ] })
502
+ ] });
503
+ }
504
+ function TextInput({
505
+ value,
506
+ onChange
507
+ }) {
508
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
509
+ "textarea",
510
+ {
511
+ className: "kaboo-interrupt-textarea",
512
+ placeholder: "Type your answer...",
513
+ value,
514
+ onChange: (e) => onChange(e.target.value),
515
+ rows: 3,
516
+ autoFocus: true
517
+ }
518
+ );
519
+ }
520
+ function FormVariant({ reason, onResolve, onCancel }) {
521
+ const questions = reason.type === "form" ? reason.questions : [];
522
+ const isSingle = questions.length === 1;
523
+ const [step, setStep] = (0, import_react4.useState)(0);
524
+ const [answers, setAnswers] = (0, import_react4.useState)({});
525
+ const [responded, setResponded] = (0, import_react4.useState)(false);
526
+ if (responded) {
527
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "kaboo-interrupt-responded", children: "Response submitted" });
528
+ }
529
+ const setAnswer = (idx, val) => {
530
+ setAnswers((prev) => ({ ...prev, [String(idx)]: val }));
531
+ };
532
+ const current = questions[step];
533
+ if (!current) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, {});
534
+ const renderQuestion = (q, idx) => {
535
+ if (q.type === "radio") {
536
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
537
+ RadioInput,
538
+ {
539
+ question: q,
540
+ value: answers[String(idx)] ?? "",
541
+ onChange: (v) => setAnswer(idx, v)
542
+ }
543
+ );
544
+ }
545
+ if (q.type === "checkbox") {
546
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
547
+ CheckboxInput,
548
+ {
549
+ question: q,
550
+ value: answers[String(idx)] ?? [],
551
+ onChange: (v) => setAnswer(idx, v)
552
+ }
553
+ );
554
+ }
555
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
556
+ TextInput,
557
+ {
558
+ value: answers[String(idx)] ?? "",
559
+ onChange: (v) => setAnswer(idx, v)
560
+ }
561
+ );
562
+ };
563
+ const isLast = step === questions.length - 1;
564
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "kaboo-interrupt kaboo-interrupt-form", children: [
565
+ !isSingle && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "kaboo-interrupt-progress", children: [
566
+ step + 1,
567
+ " of ",
568
+ questions.length
569
+ ] }),
570
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "kaboo-interrupt-question", children: current.question }),
571
+ renderQuestion(current, step),
572
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "kaboo-interrupt-actions", children: [
573
+ !isSingle && step > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
574
+ "button",
575
+ {
576
+ className: "kaboo-interrupt-btn kaboo-interrupt-btn-back",
577
+ onClick: () => setStep(step - 1),
578
+ children: "Back"
579
+ }
580
+ ),
581
+ isLast ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
582
+ "button",
583
+ {
584
+ className: "kaboo-interrupt-btn kaboo-interrupt-btn-approve",
585
+ onClick: () => {
586
+ setResponded(true);
587
+ onResolve(buildAnswerPayload(questions, answers));
588
+ },
589
+ children: "Submit"
590
+ }
591
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
592
+ "button",
593
+ {
594
+ className: "kaboo-interrupt-btn kaboo-interrupt-btn-next",
595
+ onClick: () => setStep(step + 1),
596
+ children: "Next"
597
+ }
598
+ ),
599
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
600
+ "button",
601
+ {
602
+ className: "kaboo-interrupt-btn kaboo-interrupt-btn-reject",
603
+ onClick: () => {
604
+ setResponded(true);
605
+ onCancel();
606
+ },
607
+ children: "Cancel"
608
+ }
609
+ )
610
+ ] })
611
+ ] });
612
+ }
613
+ function InterruptRenderer(props) {
614
+ if (props.reason.type === "approval") {
615
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ApprovalVariant, { ...props });
616
+ }
617
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FormVariant, { ...props });
618
+ }
619
+
620
+ // src/context/InterruptBridge.tsx
621
+ var import_react5 = require("react");
622
+ var import_jsx_runtime7 = require("react/jsx-runtime");
623
+ var InterruptBridgeContext = (0, import_react5.createContext)({
624
+ active: [],
625
+ publish: () => {
626
+ }
627
+ });
628
+ function useInterruptBridge() {
629
+ return (0, import_react5.useContext)(InterruptBridgeContext);
630
+ }
631
+ function useInterruptFor(toolCallId) {
632
+ const { active } = useInterruptBridge();
633
+ if (!toolCallId) return void 0;
634
+ return active.find((i) => i.toolCallId === toolCallId);
635
+ }
636
+ function InterruptBridgePublisher({
637
+ interrupts
638
+ }) {
639
+ const { publish } = useInterruptBridge();
640
+ const listRef = (0, import_react5.useRef)(interrupts);
641
+ listRef.current = interrupts;
642
+ const key = interrupts.map((i) => `${i.id}:${i.toolCallId ?? ""}:${JSON.stringify(i.reason)}`).join("|");
643
+ (0, import_react5.useEffect)(() => {
644
+ publish(
645
+ listRef.current.map((i) => ({
646
+ id: i.id,
647
+ reason: i.reason,
648
+ toolCallId: i.toolCallId,
649
+ onResolve: (payload) => listRef.current.find((x) => x.id === i.id)?.onResolve(payload),
650
+ onCancel: () => listRef.current.find((x) => x.id === i.id)?.onCancel()
651
+ }))
652
+ );
653
+ return () => publish([]);
654
+ }, [key, publish]);
655
+ return null;
656
+ }
657
+
658
+ // src/formatters/askUser.ts
659
+ function normalizeQuestions(params) {
660
+ if (!params) return [];
661
+ if (Array.isArray(params.questions)) {
662
+ return params.questions.map((q) => ({
663
+ question: q.question ?? "",
664
+ type: q.type ?? (q.options ? "radio" : "text"),
665
+ options: q.options
666
+ }));
667
+ }
668
+ if (typeof params.question === "string") {
669
+ return [
670
+ {
671
+ question: params.question,
672
+ type: params.input_type ?? (params.options ? "radio" : "text"),
673
+ options: params.options
674
+ }
675
+ ];
676
+ }
677
+ return [];
678
+ }
679
+ function parseAnswers(result) {
680
+ let value = result;
681
+ for (let i = 0; i < 2 && typeof value === "string"; i++) {
682
+ const trimmed = value.trim();
683
+ if (trimmed === "") return null;
684
+ try {
685
+ value = JSON.parse(trimmed);
686
+ } catch {
687
+ return null;
688
+ }
689
+ }
690
+ if (value && typeof value === "object" && !Array.isArray(value)) {
691
+ const obj = value;
692
+ return Object.keys(obj).length > 0 ? obj : null;
693
+ }
694
+ return null;
695
+ }
696
+
697
+ // src/components/Timeline.tsx
698
+ var import_jsx_runtime8 = require("react/jsx-runtime");
699
+ function AskUserTimelineRow({ tool }) {
700
+ const interrupt = useInterruptFor(tool.toolUseId);
701
+ const questions = normalizeQuestions(tool.toolInput);
702
+ const answers = parseAnswers(tool.toolResult);
703
+ if (answers) {
704
+ if (questions.length === 0) return null;
705
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AskUserSummary, { questions, answers });
706
+ }
707
+ if (interrupt && interrupt.reason.type === "form") {
708
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
709
+ InterruptRenderer,
710
+ {
711
+ reason: interrupt.reason,
712
+ toolCallId: interrupt.toolCallId,
713
+ onResolve: interrupt.onResolve,
714
+ onCancel: interrupt.onCancel
715
+ }
716
+ );
717
+ }
718
+ if (questions.length > 0 && isCancelledResult(tool.toolResult)) {
719
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AskUserSummary, { questions, answers: {}, declined: true });
720
+ }
721
+ return null;
722
+ }
723
+ function ToolTimelineRow({ tool }) {
724
+ const interrupt = useInterruptFor(tool.toolUseId);
725
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
726
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolRow, { tool }),
727
+ interrupt && interrupt.reason.type === "approval" && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
728
+ InterruptRenderer,
729
+ {
730
+ reason: interrupt.reason,
731
+ toolCallId: interrupt.toolCallId,
732
+ onResolve: interrupt.onResolve,
733
+ onCancel: interrupt.onCancel
734
+ }
735
+ )
736
+ ] });
737
+ }
738
+ function Timeline({ timeline, active, variant = "card", renderToolCard }) {
739
+ const textClass = variant === "drill" ? "kaboo-drill-tokens-content" : "kaboo-agent-card-tokens";
740
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: timeline.map((entry, i) => {
741
+ if (entry.type === "tool") {
742
+ const key = entry.tool.toolUseId || i;
743
+ const card = renderToolCard?.(entry.tool.toolUseId);
744
+ if (card) return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react6.Fragment, { children: card }, key);
745
+ if (entry.tool.toolName === "ask_user") {
746
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AskUserTimelineRow, { tool: entry.tool }, key);
747
+ }
748
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolTimelineRow, { tool: entry.tool }, key);
749
+ }
750
+ const isLast = i === timeline.length - 1;
751
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: textClass, children: [
752
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MarkdownContent, { text: entry.text }),
753
+ active && isLast && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "kaboo-blink-cursor" })
754
+ ] }, `text-${i}`);
755
+ }) });
756
+ }
757
+
758
+ // src/hooks/useDrill.ts
759
+ var import_react8 = require("react");
760
+
761
+ // src/context/DrillContext.tsx
762
+ var import_react7 = require("react");
763
+ var import_jsx_runtime9 = require("react/jsx-runtime");
764
+ var NOOP = () => {
765
+ };
766
+ var DrillContext = (0, import_react7.createContext)({
767
+ drillPath: [],
768
+ activeDrill: null,
769
+ drillIn: NOOP,
770
+ drillUp: NOOP,
771
+ drillToRoot: NOOP,
772
+ drillToLevel: NOOP
773
+ });
774
+
775
+ // src/hooks/useDrill.ts
776
+ function useDrill() {
777
+ return (0, import_react8.useContext)(DrillContext);
778
+ }
779
+
780
+ // src/utils/groups.ts
781
+ function groupTurnKey(g) {
782
+ return g.turnId ?? g.runId ?? null;
783
+ }
784
+ function partitionChildrenByToolCall(childEntries, timeline) {
785
+ const toolUseIds = new Set(
786
+ timeline.filter((e) => e.type === "tool").map((e) => e.tool.toolUseId)
787
+ );
788
+ const byToolCall = /* @__PURE__ */ new Map();
789
+ const leftover = [];
790
+ for (const [id, g] of childEntries) {
791
+ if (g.toolCallId && toolUseIds.has(g.toolCallId)) {
792
+ byToolCall.set(g.toolCallId, [id, g]);
793
+ } else {
794
+ leftover.push([id, g]);
795
+ }
796
+ }
797
+ return { byToolCall, leftover };
798
+ }
799
+ function directChildren(groups, parentId) {
800
+ return Object.entries(groups).filter(([, g]) => g.parentGroup === parentId);
801
+ }
802
+ function chatRootGroups(groups) {
803
+ return Object.entries(groups).filter(
804
+ ([, g]) => !g.toolCallId && !g.inlineChatOwner && (g.parentGroup == null || groups[g.parentGroup] === void 0)
805
+ );
806
+ }
807
+ function pendingToolAnchorExists(groups, toolCallId) {
808
+ if (!toolCallId) return false;
809
+ for (const g of Object.values(groups)) {
810
+ for (const t of g.tools) {
811
+ if (t.toolUseId === toolCallId && t.toolResult == null) {
812
+ return true;
813
+ }
814
+ }
815
+ }
816
+ return false;
817
+ }
818
+ function findGroupForCard(groups, agentName, toolCallId) {
819
+ return Object.entries(groups).find(
820
+ ([, g]) => g.agentName === agentName && g.toolCallId === toolCallId
821
+ );
822
+ }
823
+
824
+ // src/components/AgentCard.tsx
825
+ var import_jsx_runtime10 = require("react/jsx-runtime");
826
+ function AgentCard({ groupId, group, input, result, actionStatus, showChildren }) {
827
+ const { drillIn } = useDrill();
828
+ const { groups } = useActivity();
829
+ const structuredRenderers = (0, import_react9.useContext)(StructuredRenderersContext);
830
+ const childEntries = showChildren ? directChildren(groups, groupId) : [];
831
+ const isDone = group.status === "completed" || actionStatus === "complete";
832
+ const isInterrupted = group.status === "interrupted" && group.interrupt;
833
+ const [expanded, setExpanded] = (0, import_react9.useState)(true);
834
+ const prevDone = (0, import_react9.useRef)(isDone);
835
+ const bodyRef = (0, import_react9.useRef)(null);
836
+ const hasInteraction = group.tools.some((t) => t.toolName === "ask_user");
837
+ (0, import_react9.useEffect)(() => {
838
+ if (!prevDone.current && isDone && !hasInteraction) setExpanded(false);
839
+ prevDone.current = isDone;
840
+ }, [isDone, hasInteraction]);
841
+ const resultText = isControlOnlyStatus(result) ? null : normalizeResult(result);
842
+ const displayTask = input ?? group.task ?? void 0;
843
+ const timeline = showChildren && group.isChatReply ? (group.timeline ?? []).filter((e) => e.type === "tool") : group.timeline ?? [];
844
+ (0, import_react9.useEffect)(() => {
845
+ if (expanded && !isDone && bodyRef.current) {
846
+ bodyRef.current.scrollTop = bodyRef.current.scrollHeight;
847
+ }
848
+ }, [expanded, isDone, timeline]);
849
+ const { byToolCall: childByToolCall, leftover: leftoverChildren } = partitionChildrenByToolCall(childEntries, timeline);
850
+ const renderToolCard = (toolUseId) => {
851
+ const entry = childByToolCall.get(toolUseId);
852
+ if (!entry) return null;
853
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentCard, { groupId: entry[0], group: entry[1], showChildren: true });
854
+ };
855
+ const hasContent = timeline.length > 0 || resultText || childEntries.length > 0 || !!displayTask;
856
+ const cardClass = `kaboo-agent-card${isDone ? " kaboo-agent-card-done" : ""}`;
857
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: cardClass, children: [
858
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "kaboo-agent-card-header", onClick: () => setExpanded(!expanded), children: [
859
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "kaboo-agent-card-title-area", children: [
860
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "kaboo-agent-card-title-row", children: [
861
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "kaboo-agent-card-title", children: group.title }),
862
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: `kaboo-status-badge ${isDone ? "kaboo-status-done" : isInterrupted ? "kaboo-status-interrupted" : "kaboo-status-active"}`, children: [
863
+ isDone ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { width: 10, height: 10, viewBox: "0 0 16 16", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M3.5 8.5L6.5 11.5L12.5 4.5", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) : isInterrupted ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: 10, height: 10, viewBox: "0 0 16 16", children: [
864
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("circle", { cx: "8", cy: "8", r: "7", fill: "none", stroke: "currentColor", strokeWidth: "1.5" }),
865
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M8 4.5v4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }),
866
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("circle", { cx: "8", cy: "11", r: "0.75", fill: "currentColor" })
867
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { width: 10, height: 10, viewBox: "0 0 16 16", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("circle", { cx: "8", cy: "8", r: "5", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeDasharray: "22", strokeDashoffset: "6", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("animateTransform", { attributeName: "transform", type: "rotate", from: "0 8 8", to: "360 8 8", dur: "0.8s", repeatCount: "indefinite" }) }) }),
868
+ isDone ? "done" : isInterrupted ? "needs input" : "working..."
869
+ ] })
870
+ ] }),
871
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "kaboo-agent-card-subtitle", children: group.agentName })
872
+ ] }),
873
+ group.tools.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: `kaboo-tool-count ${isDone ? "kaboo-tool-count-done" : ""}`, children: [
874
+ group.tools.length,
875
+ " tool",
876
+ group.tools.length !== 1 ? "s" : ""
877
+ ] }),
878
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
879
+ "svg",
880
+ {
881
+ width: 14,
882
+ height: 14,
883
+ viewBox: "0 0 16 16",
884
+ className: `kaboo-chevron ${expanded ? "kaboo-chevron-open" : ""}`,
885
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M4 6l4 4 4-4", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
886
+ }
887
+ )
888
+ ] }),
889
+ !expanded && displayTask && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "kaboo-agent-card-collapsed", children: [
890
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: "Task:" }),
891
+ " ",
892
+ displayTask
893
+ ] }),
894
+ expanded && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref: bodyRef, className: "kaboo-agent-card-body", children: [
895
+ displayTask && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "kaboo-agent-card-task", children: [
896
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: "Task:" }),
897
+ " ",
898
+ displayTask
899
+ ] }),
900
+ timeline.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "kaboo-agent-card-timeline", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Timeline, { timeline, active: !isDone, variant: "card", renderToolCard }) }),
901
+ resultText && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "kaboo-agent-card-result", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MarkdownContent, { text: resultText }) }),
902
+ group.structuredOutput && group.outputSchemaName && (() => {
903
+ const Renderer = structuredRenderers[group.outputSchemaName];
904
+ if (Renderer) {
905
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Renderer, { ...group.structuredOutput });
906
+ }
907
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("details", { className: "kaboo-agent-card-structured", children: [
908
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("summary", { className: "kaboo-agent-card-structured-summary", children: [
909
+ "Structured output (",
910
+ group.outputSchemaName,
911
+ ")"
912
+ ] }),
913
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("pre", { className: "kaboo-agent-card-structured-pre", children: JSON.stringify(group.structuredOutput, null, 2) })
914
+ ] });
915
+ })(),
916
+ leftoverChildren.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "kaboo-agent-card-children", children: leftoverChildren.map(([childId, child]) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
917
+ AgentCard,
918
+ {
919
+ groupId: childId,
920
+ group: child,
921
+ showChildren: true
922
+ },
923
+ childId
924
+ )) }),
925
+ !displayTask && !hasContent && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "kaboo-agent-card-empty", children: "Working..." })
926
+ ] }),
927
+ hasContent && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
928
+ "button",
929
+ {
930
+ className: "kaboo-drill-btn",
931
+ onClick: (e) => {
932
+ e.stopPropagation();
933
+ drillIn(groupId);
934
+ },
935
+ children: [
936
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "View details" }),
937
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { width: 12, height: 12, viewBox: "0 0 16 16", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M6 4l4 4-4 4", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) })
938
+ ]
939
+ }
940
+ )
941
+ ] });
942
+ }
943
+
944
+ // src/integrations/KabooToolRender.tsx
945
+ var import_v22 = require("@copilotkit/react-core/v2");
946
+ var import_jsx_runtime11 = require("react/jsx-runtime");
947
+ function findTool(groups, toolCallId) {
948
+ for (const group of Object.values(groups)) {
949
+ const match = group.tools.find((t) => t.toolUseId === toolCallId);
950
+ if (match) return match;
951
+ }
952
+ return void 0;
953
+ }
954
+ function isDelegateSpawn(groups, name, toolCallId) {
955
+ for (const group of Object.values(groups)) {
956
+ if (!group.toolCallId) continue;
957
+ if (group.toolCallId === toolCallId || group.agentName === name) return true;
958
+ }
959
+ return false;
960
+ }
961
+ function KabooToolRender() {
962
+ const { groups } = useActivity();
963
+ (0, import_v22.useDefaultRenderTool)(
964
+ {
965
+ render: ({ name, toolCallId, parameters, status, result }) => {
966
+ if (isDelegateSpawn(groups, name, toolCallId)) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, {});
967
+ const fromActivity = findTool(groups, toolCallId);
968
+ const controlEcho = !fromActivity && isControlOnlyStatus(result);
969
+ const tool = fromActivity ?? {
970
+ toolUseId: toolCallId,
971
+ toolName: name,
972
+ toolInput: parameters,
973
+ toolResult: controlEcho || typeof result !== "string" ? void 0 : result,
974
+ status: status === "complete" ? "success" : "running"
975
+ };
976
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "kaboo-inline-tool", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ToolRow, { tool }) });
977
+ }
978
+ },
979
+ [groups]
980
+ );
981
+ return null;
982
+ }
983
+
984
+ // src/integrations/KabooInlineCards.tsx
985
+ var import_jsx_runtime12 = require("react/jsx-runtime");
986
+ var ANY_PARAMETERS = {
987
+ "~standard": {
988
+ version: 1,
989
+ vendor: "kaboo",
990
+ validate: (value) => ({ value })
991
+ }
992
+ };
993
+ function KabooInlineCards() {
994
+ const { groups } = useActivity();
995
+ const toolAgentNames = /* @__PURE__ */ new Set();
996
+ for (const group of Object.values(groups)) {
997
+ if (group.agentName && group.toolCallId) toolAgentNames.add(group.agentName);
998
+ }
999
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1000
+ Array.from(toolAgentNames).map((agentName) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(InlineCardAction, { agentName }, agentName)),
1001
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(KabooToolRender, {})
1002
+ ] });
1003
+ }
1004
+ function InlineCardAction({ agentName }) {
1005
+ (0, import_v23.useRenderTool)({
1006
+ name: agentName,
1007
+ parameters: ANY_PARAMETERS,
1008
+ render: ({ toolCallId, parameters, result, status }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1009
+ InlineCardRenderer,
1010
+ {
1011
+ agentName,
1012
+ toolCallId,
1013
+ input: parameters?.input,
1014
+ result: typeof result === "string" ? result : void 0,
1015
+ actionStatus: status
1016
+ }
1017
+ )
1018
+ });
1019
+ return null;
1020
+ }
1021
+ function InlineCardRenderer({
1022
+ agentName,
1023
+ toolCallId,
1024
+ input,
1025
+ result,
1026
+ actionStatus
1027
+ }) {
1028
+ const { groups } = useActivity();
1029
+ const entry = findGroupForCard(groups, agentName, toolCallId);
1030
+ if (!entry) {
1031
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "kaboo-agent-card-empty", children: [
1032
+ "Loading ",
1033
+ agentName,
1034
+ "..."
1035
+ ] });
1036
+ }
1037
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1038
+ AgentCard,
1039
+ {
1040
+ groupId: entry[0],
1041
+ group: entry[1],
1042
+ input,
1043
+ result,
1044
+ actionStatus
1045
+ }
1046
+ );
1047
+ }
1048
+
1049
+ // src/integrations/KabooAssistantMessage.tsx
1050
+ var import_v24 = require("@copilotkit/react-core/v2");
1051
+
1052
+ // src/context/TurnBinding.tsx
1053
+ var import_react10 = require("react");
1054
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1055
+ var TurnBindingContext = (0, import_react10.createContext)({
1056
+ rootsByMessageId: /* @__PURE__ */ new Map()
1057
+ });
1058
+ function TurnBindingProvider({
1059
+ value,
1060
+ children
1061
+ }) {
1062
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TurnBindingContext.Provider, { value, children });
1063
+ }
1064
+ function useTurnBinding() {
1065
+ return (0, import_react10.useContext)(TurnBindingContext);
1066
+ }
1067
+
1068
+ // src/integrations/KabooAssistantMessage.tsx
1069
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1070
+ function KabooAssistantMessage(props) {
1071
+ const { message } = props;
1072
+ const { rootsByMessageId } = useTurnBinding();
1073
+ const messageId = message?.id;
1074
+ const mine = messageId ? rootsByMessageId.get(messageId) ?? [] : [];
1075
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1076
+ mine.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "kaboo-inline-cards", children: mine.map(([groupId, group]) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AgentCard, { groupId, group, showChildren: true }, groupId)) }),
1077
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_v24.CopilotChatAssistantMessage, { ...props })
1078
+ ] });
1079
+ }
1080
+
1081
+ // src/integrations/KabooMessageView.tsx
1082
+ var import_v25 = require("@copilotkit/react-core/v2");
1083
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1084
+ function KabooMessageViewImpl(props) {
1085
+ const { groups } = useActivity();
1086
+ const { copilotkit } = (0, import_v25.useCopilotKit)();
1087
+ const config = (0, import_v25.useCopilotChatConfiguration)();
1088
+ const agentId = config?.agentId;
1089
+ const threadId = config?.threadId;
1090
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1091
+ import_v25.CopilotChatMessageView,
1092
+ {
1093
+ ...props,
1094
+ assistantMessage: KabooAssistantMessage,
1095
+ children: ({ messages, messageElements, interruptElement, isRunning }) => {
1096
+ const roots = chatRootGroups(groups);
1097
+ const rootsByTurn = /* @__PURE__ */ new Map();
1098
+ for (const entry of roots) {
1099
+ const key = groupTurnKey(entry[1]);
1100
+ if (!key) continue;
1101
+ const bucket = rootsByTurn.get(key);
1102
+ if (bucket) bucket.push(entry);
1103
+ else rootsByTurn.set(key, [entry]);
1104
+ }
1105
+ const runToTurn = /* @__PURE__ */ new Map();
1106
+ for (const g of Object.values(groups)) {
1107
+ const key = groupTurnKey(g);
1108
+ if (g.runId && key) runToTurn.set(g.runId, key);
1109
+ }
1110
+ const rootsByMessageId = /* @__PURE__ */ new Map();
1111
+ const boundTurns = /* @__PURE__ */ new Set();
1112
+ const list = messages;
1113
+ for (const m of list) {
1114
+ if (m?.role !== "assistant" || !m.id) continue;
1115
+ const runId = agentId && threadId ? copilotkit.getRunIdForMessage(agentId, threadId, m.id) : void 0;
1116
+ const key = runId ? runToTurn.get(runId) ?? runId : void 0;
1117
+ if (!key) continue;
1118
+ const turnRoots = rootsByTurn.get(key);
1119
+ if (turnRoots) {
1120
+ rootsByMessageId.set(m.id, turnRoots);
1121
+ boundTurns.add(key);
1122
+ }
1123
+ }
1124
+ const pending = roots.filter(([, g]) => {
1125
+ const key = groupTurnKey(g);
1126
+ return !key || !boundTurns.has(key);
1127
+ });
1128
+ const showStartCursor = isRunning && pending.length === 0;
1129
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(TurnBindingProvider, { value: { rootsByMessageId }, children: [
1130
+ messageElements,
1131
+ pending.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "kaboo-inline-cards", children: pending.map(([groupId, group]) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AgentCard, { groupId, group, showChildren: true }, groupId)) }),
1132
+ interruptElement,
1133
+ showStartCursor && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_v25.CopilotChatMessageView.Cursor, {})
1134
+ ] });
1135
+ }
1136
+ }
1137
+ );
1138
+ }
1139
+ var KabooMessageView = Object.assign(KabooMessageViewImpl, {
1140
+ /**
1141
+ * The streaming cursor slot, re-exported from CopilotKit so `KabooMessageView`
1142
+ * is a drop-in `messageView` (the slot expects a component carrying `Cursor`).
1143
+ */
1144
+ Cursor: import_v25.CopilotChatMessageView.Cursor
1145
+ });
1146
+
1147
+ // src/integrations/KabooInterruptHandler.tsx
1148
+ var import_v27 = require("@copilotkit/react-core/v2");
1149
+
1150
+ // src/integrations/KabooAskUser.tsx
1151
+ var import_v26 = require("@copilotkit/react-core/v2");
1152
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1153
+ var ANY_PARAMETERS2 = {
1154
+ "~standard": {
1155
+ version: 1,
1156
+ vendor: "kaboo",
1157
+ validate: (value) => ({ value })
1158
+ }
1159
+ };
1160
+ function KabooAskUser({ agentId }) {
1161
+ (0, import_v26.useRenderTool)({
1162
+ name: "ask_user",
1163
+ ...agentId ? { agentId } : {},
1164
+ parameters: ANY_PARAMETERS2,
1165
+ render: ({ parameters, result }) => {
1166
+ const questions = normalizeQuestions(parameters);
1167
+ if (questions.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, {});
1168
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AskUserCard, { questions, result });
1169
+ }
1170
+ });
1171
+ return null;
1172
+ }
1173
+ function AskUserCard({
1174
+ questions,
1175
+ result
1176
+ }) {
1177
+ const answers = parseAnswers(result);
1178
+ if (!answers) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, {});
1179
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AskUserSummary, { questions, answers });
1180
+ }
1181
+
1182
+ // src/integrations/KabooInterruptHandler.tsx
1183
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1184
+ function ChatInterruptSlot({
1185
+ interrupt,
1186
+ Renderer
1187
+ }) {
1188
+ const { groups } = useActivity();
1189
+ if (pendingToolAnchorExists(groups, interrupt.toolCallId)) {
1190
+ return null;
1191
+ }
1192
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1193
+ Renderer,
1194
+ {
1195
+ reason: interrupt.reason,
1196
+ toolCallId: interrupt.toolCallId,
1197
+ onResolve: interrupt.onResolve,
1198
+ onCancel: interrupt.onCancel
1199
+ }
1200
+ );
1201
+ }
1202
+ function KabooInterruptHandler({
1203
+ agentId,
1204
+ renderers,
1205
+ bridge = true
1206
+ }) {
1207
+ (0, import_v27.useInterrupt)({
1208
+ ...agentId ? { agentId } : {},
1209
+ render: ({ interrupts, resolve, cancel }) => {
1210
+ const active = (interrupts ?? []).map((intr) => {
1211
+ const reason = intr?.metadata ?? intr?.reason;
1212
+ if (!reason || !reason.type) return null;
1213
+ return {
1214
+ id: intr.id,
1215
+ reason,
1216
+ toolCallId: intr.toolCallId,
1217
+ onResolve: (payload) => resolve(payload, intr.id),
1218
+ onCancel: () => cancel(intr.id)
1219
+ };
1220
+ }).filter((x) => x !== null);
1221
+ if (active.length === 0) {
1222
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, {});
1223
+ }
1224
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1225
+ bridge && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(InterruptBridgePublisher, { interrupts: active }),
1226
+ active.map((a) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1227
+ ChatInterruptSlot,
1228
+ {
1229
+ interrupt: a,
1230
+ Renderer: renderers?.[a.reason.type] ?? InterruptRenderer
1231
+ },
1232
+ a.id
1233
+ ))
1234
+ ] });
1235
+ }
1236
+ });
1237
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(KabooAskUser, { agentId });
1238
+ }
1239
+ // Annotate the CommonJS export names for ESM import in node:
1240
+ 0 && (module.exports = {
1241
+ KabooAskUser,
1242
+ KabooAssistantMessage,
1243
+ KabooInlineCards,
1244
+ KabooInterruptHandler,
1245
+ KabooMessageView,
1246
+ KabooToolRender
1247
+ });
1248
+ //# sourceMappingURL=copilotkit.cjs.map