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