@kodaris/krubble-app-components 1.0.116 → 1.0.117
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chatbot.d.ts +71 -3
- package/dist/chatbot.d.ts.map +1 -1
- package/dist/chatbot.js +495 -12
- package/dist/chatbot.js.map +1 -1
- package/dist/krubble-app.bundled.js +493 -12
- package/dist/krubble-app.bundled.js.map +1 -1
- package/dist/krubble-app.bundled.min.js +278 -32
- package/dist/krubble-app.bundled.min.js.map +1 -1
- package/dist/krubble-app.umd.js +493 -12
- package/dist/krubble-app.umd.js.map +1 -1
- package/dist/krubble-app.umd.min.js +277 -31
- package/dist/krubble-app.umd.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -5851,11 +5851,26 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
5851
5851
|
*/
|
|
5852
5852
|
this._drawerOpen = false;
|
|
5853
5853
|
/**
|
|
5854
|
-
* Which view the drawer shows — settings or
|
|
5855
|
-
*
|
|
5856
|
-
*
|
|
5854
|
+
* Which view the drawer shows — settings, debug, or a single tool call's full
|
|
5855
|
+
* detail. One drawer holds all three; the header buttons switch settings/debug
|
|
5856
|
+
* and clicking a tool line switches to `toolDetail`. The content/width swap
|
|
5857
|
+
* inside. Never null, so the content stays visible while the drawer slides shut.
|
|
5857
5858
|
*/
|
|
5858
5859
|
this._drawerView = 'settings';
|
|
5860
|
+
/**
|
|
5861
|
+
* The tool call whose full input/output the `toolDetail` drawer view shows —
|
|
5862
|
+
* the clicked `tool_use` message and its paired `tool_result` message, stored
|
|
5863
|
+
* whole. The render reads `.data.*` off them (and formats for display) so we
|
|
5864
|
+
* don't duplicate the message shape here. Transient — set on click, never
|
|
5865
|
+
* persisted (its bytes can be large and the view is a peek). Null when none.
|
|
5866
|
+
*/
|
|
5867
|
+
this._toolDetail = null;
|
|
5868
|
+
/** Which tool-detail block ('input' | 'output') just flashed "Copied" (null = none). */
|
|
5869
|
+
this._toolDetailCopied = null;
|
|
5870
|
+
/** Whether the tool-detail Input section is expanded. Both open on open. */
|
|
5871
|
+
this._toolDetailInputOpen = true;
|
|
5872
|
+
/** Whether the tool-detail Output section is expanded. */
|
|
5873
|
+
this._toolDetailOutputOpen = true;
|
|
5859
5874
|
/** Current width of the drawer in px (user-resizable, persisted). */
|
|
5860
5875
|
this._drawerWidth = 430;
|
|
5861
5876
|
/** True while the user is dragging the drawer's resize handle. */
|
|
@@ -6374,6 +6389,12 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6374
6389
|
}
|
|
6375
6390
|
_saveState() {
|
|
6376
6391
|
try {
|
|
6392
|
+
// `toolDetail` is a transient peek, not a saved view — persist only the two
|
|
6393
|
+
// real preference views so a reload never reopens a stale tool.
|
|
6394
|
+
let persistedDrawerView = this._drawerView;
|
|
6395
|
+
if (persistedDrawerView === 'toolDetail') {
|
|
6396
|
+
persistedDrawerView = 'settings';
|
|
6397
|
+
}
|
|
6377
6398
|
const state = {
|
|
6378
6399
|
opened: String(this.opened),
|
|
6379
6400
|
message: this._inputValue,
|
|
@@ -6382,7 +6403,7 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6382
6403
|
showToolInputs: String(this._showToolInputs),
|
|
6383
6404
|
showConfirmationInput: String(this._showConfirmationInput),
|
|
6384
6405
|
drawerOpen: String(this._drawerOpen),
|
|
6385
|
-
drawerView:
|
|
6406
|
+
drawerView: persistedDrawerView,
|
|
6386
6407
|
drawerWidth: String(this._drawerWidth),
|
|
6387
6408
|
};
|
|
6388
6409
|
if (this._panelEl) {
|
|
@@ -7525,6 +7546,162 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
7525
7546
|
this._drawerOpen = false;
|
|
7526
7547
|
this._saveState();
|
|
7527
7548
|
}
|
|
7549
|
+
/**
|
|
7550
|
+
* Open the drawer to a single tool call's full input/output. Called when the
|
|
7551
|
+
* user clicks a tool-activity line in the transcript. Independent of the
|
|
7552
|
+
* `_showToolInputs` setting — this is the on-demand "show me everything for
|
|
7553
|
+
* THIS call" peek, so it works even when inline inputs are hidden. `result` is
|
|
7554
|
+
* the paired `tool_result` message data (may be absent if the tool hasn't
|
|
7555
|
+
* returned yet).
|
|
7556
|
+
*/
|
|
7557
|
+
_openToolDetail(use) {
|
|
7558
|
+
// Pair the tool_use to the tool_result that immediately follows it (matched by
|
|
7559
|
+
// toolUseId) — the same pairing the transcript render uses for the ⎿ preview.
|
|
7560
|
+
const next = this.messages[this.messages.indexOf(use) + 1];
|
|
7561
|
+
this._toolDetail = {
|
|
7562
|
+
use,
|
|
7563
|
+
result: null,
|
|
7564
|
+
};
|
|
7565
|
+
if (next?.type === 'tool_result' && next.data?.toolUseId === use.data?.toolUseId) {
|
|
7566
|
+
this._toolDetail.result = next;
|
|
7567
|
+
}
|
|
7568
|
+
this._toolDetailCopied = null;
|
|
7569
|
+
this._toolDetailInputOpen = true;
|
|
7570
|
+
this._toolDetailOutputOpen = true;
|
|
7571
|
+
this._drawerView = 'toolDetail';
|
|
7572
|
+
this._drawerOpen = true;
|
|
7573
|
+
this._saveState();
|
|
7574
|
+
// Reset the panel scroll so a newly-opened tool starts at the top, rather
|
|
7575
|
+
// than inheriting the previous tool's scroll position. Wait for the render.
|
|
7576
|
+
this.updateComplete.then(() => {
|
|
7577
|
+
if (this._drawerBodyEl) {
|
|
7578
|
+
this._drawerBodyEl.scrollTop = 0;
|
|
7579
|
+
}
|
|
7580
|
+
});
|
|
7581
|
+
}
|
|
7582
|
+
/** Toggle the tool-detail Input section open/closed. */
|
|
7583
|
+
_handleToggleToolDetailInput() {
|
|
7584
|
+
this._toolDetailInputOpen = !this._toolDetailInputOpen;
|
|
7585
|
+
}
|
|
7586
|
+
/** Toggle the tool-detail Output section open/closed. */
|
|
7587
|
+
_handleToggleToolDetailOutput() {
|
|
7588
|
+
this._toolDetailOutputOpen = !this._toolDetailOutputOpen;
|
|
7589
|
+
}
|
|
7590
|
+
/**
|
|
7591
|
+
* Pretty-print a tool input/result for the detail view. The values arrive as
|
|
7592
|
+
* strings that usually hold JSON; reindent when they do, otherwise show as-is.
|
|
7593
|
+
* Never throws — falls back to the original text.
|
|
7594
|
+
*
|
|
7595
|
+
* A large/overflowing result is stashed server-side and returned as a preview
|
|
7596
|
+
* wrapped in `<<<uuid_BEGIN>>> … <<<uuid_END>>>` markers, followed by a paging
|
|
7597
|
+
* note. Two things make `JSON.parse` unusable here: the marker wrapper isn't
|
|
7598
|
+
* JSON, and the payload between the markers is a truncated SLICE of a bigger
|
|
7599
|
+
* blob (cut off mid-string), so it never parses on its own. So we reindent the
|
|
7600
|
+
* payload STRUCTURALLY (see `_reindentJson`) rather than parse it, and keep the
|
|
7601
|
+
* markers + note exactly where they were so it still reads as a paged response.
|
|
7602
|
+
*/
|
|
7603
|
+
_formatToolJson(value) {
|
|
7604
|
+
if (value === undefined || value === null) {
|
|
7605
|
+
return '';
|
|
7606
|
+
}
|
|
7607
|
+
const raw = String(value);
|
|
7608
|
+
const marker = raw.match(/(<<<[0-9a-f-]+_BEGIN>>>\n?)([\s\S]*?)(\n?<<<[0-9a-f-]+_END>>>)/);
|
|
7609
|
+
if (marker && marker.index != null) {
|
|
7610
|
+
// Splice by index rather than String.replace — the reindented JSON can
|
|
7611
|
+
// contain `$` sequences (e.g. "$dtoRef") that replace() treats as special.
|
|
7612
|
+
const start = marker.index + marker[1].length;
|
|
7613
|
+
const end = start + marker[2].length;
|
|
7614
|
+
return raw.slice(0, start) + this._reindentJson(marker[2]) + raw.slice(end);
|
|
7615
|
+
}
|
|
7616
|
+
return this._reindentJson(raw);
|
|
7617
|
+
}
|
|
7618
|
+
/**
|
|
7619
|
+
* Reindent JSON-ish text for display. Tries a strict parse+stringify first (the
|
|
7620
|
+
* clean path for complete, valid JSON). If that fails — which it does for the
|
|
7621
|
+
* truncated slices returned by the stashed-response pager — it falls back to a
|
|
7622
|
+
* structural walk that inserts newlines/indentation around `{}[],:` while
|
|
7623
|
+
* tracking string state (so braces and commas INSIDE string values, and escaped
|
|
7624
|
+
* quotes, are left alone). This formats even incomplete JSON. Non-JSON text
|
|
7625
|
+
* (no leading `{`/`[`) is returned untouched.
|
|
7626
|
+
*/
|
|
7627
|
+
_reindentJson(text) {
|
|
7628
|
+
const trimmed = text.trim();
|
|
7629
|
+
if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
|
|
7630
|
+
return text;
|
|
7631
|
+
}
|
|
7632
|
+
try {
|
|
7633
|
+
return JSON.stringify(JSON.parse(trimmed), null, 2);
|
|
7634
|
+
}
|
|
7635
|
+
catch {
|
|
7636
|
+
// Fall through to the tolerant structural reindent below.
|
|
7637
|
+
}
|
|
7638
|
+
let out = '';
|
|
7639
|
+
let depth = 0;
|
|
7640
|
+
let inString = false;
|
|
7641
|
+
let escaped = false;
|
|
7642
|
+
const pad = (level) => '\n' + ' '.repeat(Math.max(0, level));
|
|
7643
|
+
for (let i = 0; i < trimmed.length; i++) {
|
|
7644
|
+
const ch = trimmed[i];
|
|
7645
|
+
if (inString) {
|
|
7646
|
+
out += ch;
|
|
7647
|
+
if (escaped) {
|
|
7648
|
+
escaped = false;
|
|
7649
|
+
}
|
|
7650
|
+
else if (ch === '\\') {
|
|
7651
|
+
escaped = true;
|
|
7652
|
+
}
|
|
7653
|
+
else if (ch === '"') {
|
|
7654
|
+
inString = false;
|
|
7655
|
+
}
|
|
7656
|
+
continue;
|
|
7657
|
+
}
|
|
7658
|
+
if (ch === '"') {
|
|
7659
|
+
inString = true;
|
|
7660
|
+
out += ch;
|
|
7661
|
+
}
|
|
7662
|
+
else if (ch === '{' || ch === '[') {
|
|
7663
|
+
depth++;
|
|
7664
|
+
out += ch + pad(depth);
|
|
7665
|
+
}
|
|
7666
|
+
else if (ch === '}' || ch === ']') {
|
|
7667
|
+
depth--;
|
|
7668
|
+
out += pad(depth) + ch;
|
|
7669
|
+
}
|
|
7670
|
+
else if (ch === ',') {
|
|
7671
|
+
out += ch + pad(depth);
|
|
7672
|
+
}
|
|
7673
|
+
else if (ch === ':') {
|
|
7674
|
+
out += ': ';
|
|
7675
|
+
}
|
|
7676
|
+
else if (ch === ' ' || ch === '\n' || ch === '\t' || ch === '\r') ;
|
|
7677
|
+
else {
|
|
7678
|
+
out += ch;
|
|
7679
|
+
}
|
|
7680
|
+
}
|
|
7681
|
+
return out;
|
|
7682
|
+
}
|
|
7683
|
+
/** Copy the tool-detail Input to the clipboard. Stops propagation so the click
|
|
7684
|
+
* doesn't also toggle the (parent) section header. */
|
|
7685
|
+
_handleCopyToolDetailInput(e) {
|
|
7686
|
+
e.stopPropagation();
|
|
7687
|
+
this._copyToolDetail('input', this._formatToolJson(this._toolDetail?.use.data?.toolInput));
|
|
7688
|
+
}
|
|
7689
|
+
/** Copy the tool-detail Output to the clipboard (see input handler). */
|
|
7690
|
+
_handleCopyToolDetailOutput(e) {
|
|
7691
|
+
e.stopPropagation();
|
|
7692
|
+
this._copyToolDetail('output', this._formatToolJson(this._toolDetail?.result?.data?.toolResultString));
|
|
7693
|
+
}
|
|
7694
|
+
/** Write one tool-detail block to the clipboard and flash "Copied" on it. */
|
|
7695
|
+
_copyToolDetail(block, content) {
|
|
7696
|
+
navigator.clipboard.writeText(content).then(() => {
|
|
7697
|
+
this._toolDetailCopied = block;
|
|
7698
|
+
setTimeout(() => {
|
|
7699
|
+
if (this._toolDetailCopied === block) {
|
|
7700
|
+
this._toolDetailCopied = null;
|
|
7701
|
+
}
|
|
7702
|
+
}, 2000);
|
|
7703
|
+
}).catch(() => { });
|
|
7704
|
+
}
|
|
7528
7705
|
_handleDrawerResizeMouseDown(e) {
|
|
7529
7706
|
this._isDrawerResizing = true;
|
|
7530
7707
|
this._drawerResizeStartX = e.clientX;
|
|
@@ -8131,6 +8308,16 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
8131
8308
|
const isDebug = this._drawerView === 'debug'
|
|
8132
8309
|
&& this.variant === 'inline'
|
|
8133
8310
|
&& this._aiFrameworkConfig.debugTelemetryEnabled === true;
|
|
8311
|
+
let title = 'Settings';
|
|
8312
|
+
let body = this._renderSettingsContent();
|
|
8313
|
+
if (isDebug) {
|
|
8314
|
+
title = 'Debug';
|
|
8315
|
+
body = this._renderDebugContent();
|
|
8316
|
+
}
|
|
8317
|
+
else if (this._drawerView === 'toolDetail' && this._toolDetail) {
|
|
8318
|
+
title = this._toolDetail.use.data?.displayName || this._toolDetail.use.data?.toolName || 'Tool';
|
|
8319
|
+
body = this._renderToolDetailContent();
|
|
8320
|
+
}
|
|
8134
8321
|
return b `
|
|
8135
8322
|
<div
|
|
8136
8323
|
class=${e({
|
|
@@ -8145,7 +8332,7 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
8145
8332
|
@mousedown=${this._handleDrawerResizeMouseDown}
|
|
8146
8333
|
></div>
|
|
8147
8334
|
<div class="drawer__header">
|
|
8148
|
-
<span class="drawer__title">${
|
|
8335
|
+
<span class="drawer__title">${title}</span>
|
|
8149
8336
|
<button
|
|
8150
8337
|
class="header-action"
|
|
8151
8338
|
@click=${this._handleCloseDrawer}
|
|
@@ -8168,7 +8355,7 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
8168
8355
|
</button>
|
|
8169
8356
|
</div>
|
|
8170
8357
|
<div class="drawer__body">
|
|
8171
|
-
${
|
|
8358
|
+
${body}
|
|
8172
8359
|
</div>
|
|
8173
8360
|
</div>
|
|
8174
8361
|
`;
|
|
@@ -8202,6 +8389,129 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
8202
8389
|
</div>
|
|
8203
8390
|
`;
|
|
8204
8391
|
}
|
|
8392
|
+
/**
|
|
8393
|
+
* The Tool detail view's body — the full input and output for one tool call,
|
|
8394
|
+
* pretty-printed in scrollable code blocks with a per-block copy button. This
|
|
8395
|
+
* is the "occasionally see everything" path: the transcript stays terse, and
|
|
8396
|
+
* clicking a tool line drops its complete input/output here, uncapped (the
|
|
8397
|
+
* blocks scroll rather than truncating).
|
|
8398
|
+
*/
|
|
8399
|
+
_renderToolDetailContent() {
|
|
8400
|
+
return b `
|
|
8401
|
+
<div class="tool-detail">
|
|
8402
|
+
<div class="tool-detail__section">
|
|
8403
|
+
<button
|
|
8404
|
+
type="button"
|
|
8405
|
+
class="tool-detail__section-head"
|
|
8406
|
+
aria-expanded=${this._toolDetailInputOpen}
|
|
8407
|
+
@click=${this._handleToggleToolDetailInput}
|
|
8408
|
+
>
|
|
8409
|
+
<span class=${e({
|
|
8410
|
+
'tool-detail__caret': true,
|
|
8411
|
+
'tool-detail__caret--open': this._toolDetailInputOpen,
|
|
8412
|
+
})}>›</span>
|
|
8413
|
+
<span class="tool-detail__section-title">Input</span>
|
|
8414
|
+
<span
|
|
8415
|
+
class="tool-detail__copy"
|
|
8416
|
+
role="button"
|
|
8417
|
+
@click=${this._handleCopyToolDetailInput}
|
|
8418
|
+
>
|
|
8419
|
+
${this._toolDetailCopied === 'input'
|
|
8420
|
+
? b `
|
|
8421
|
+
<svg
|
|
8422
|
+
viewBox="0 0 24 24"
|
|
8423
|
+
fill="none"
|
|
8424
|
+
stroke="currentColor"
|
|
8425
|
+
stroke-width="1.5"
|
|
8426
|
+
stroke-linecap="round"
|
|
8427
|
+
stroke-linejoin="round"
|
|
8428
|
+
>
|
|
8429
|
+
<path d="M20 6 9 17l-5-5" />
|
|
8430
|
+
</svg>
|
|
8431
|
+
`
|
|
8432
|
+
: b `
|
|
8433
|
+
<svg
|
|
8434
|
+
viewBox="0 0 24 24"
|
|
8435
|
+
fill="none"
|
|
8436
|
+
stroke="currentColor"
|
|
8437
|
+
stroke-width="1.5"
|
|
8438
|
+
stroke-linecap="round"
|
|
8439
|
+
stroke-linejoin="round"
|
|
8440
|
+
>
|
|
8441
|
+
<rect
|
|
8442
|
+
x="9"
|
|
8443
|
+
y="9"
|
|
8444
|
+
width="13"
|
|
8445
|
+
height="13"
|
|
8446
|
+
rx="2"
|
|
8447
|
+
/>
|
|
8448
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
|
|
8449
|
+
</svg>
|
|
8450
|
+
`}
|
|
8451
|
+
</span>
|
|
8452
|
+
</button>
|
|
8453
|
+
${this._toolDetailInputOpen
|
|
8454
|
+
? b `<pre class="tool-detail__code">${this._formatToolJson(this._toolDetail.use.data?.toolInput) || '(no input)'}</pre>`
|
|
8455
|
+
: A}
|
|
8456
|
+
</div>
|
|
8457
|
+
<div class="tool-detail__section">
|
|
8458
|
+
<button
|
|
8459
|
+
type="button"
|
|
8460
|
+
class="tool-detail__section-head"
|
|
8461
|
+
aria-expanded=${this._toolDetailOutputOpen}
|
|
8462
|
+
@click=${this._handleToggleToolDetailOutput}
|
|
8463
|
+
>
|
|
8464
|
+
<span class=${e({
|
|
8465
|
+
'tool-detail__caret': true,
|
|
8466
|
+
'tool-detail__caret--open': this._toolDetailOutputOpen,
|
|
8467
|
+
})}>›</span>
|
|
8468
|
+
<span class="tool-detail__section-title">Output</span>
|
|
8469
|
+
<span
|
|
8470
|
+
class="tool-detail__copy"
|
|
8471
|
+
role="button"
|
|
8472
|
+
@click=${this._handleCopyToolDetailOutput}
|
|
8473
|
+
>
|
|
8474
|
+
${this._toolDetailCopied === 'output'
|
|
8475
|
+
? b `
|
|
8476
|
+
<svg
|
|
8477
|
+
viewBox="0 0 24 24"
|
|
8478
|
+
fill="none"
|
|
8479
|
+
stroke="currentColor"
|
|
8480
|
+
stroke-width="1.5"
|
|
8481
|
+
stroke-linecap="round"
|
|
8482
|
+
stroke-linejoin="round"
|
|
8483
|
+
>
|
|
8484
|
+
<path d="M20 6 9 17l-5-5" />
|
|
8485
|
+
</svg>
|
|
8486
|
+
`
|
|
8487
|
+
: b `
|
|
8488
|
+
<svg
|
|
8489
|
+
viewBox="0 0 24 24"
|
|
8490
|
+
fill="none"
|
|
8491
|
+
stroke="currentColor"
|
|
8492
|
+
stroke-width="1.5"
|
|
8493
|
+
stroke-linecap="round"
|
|
8494
|
+
stroke-linejoin="round"
|
|
8495
|
+
>
|
|
8496
|
+
<rect
|
|
8497
|
+
x="9"
|
|
8498
|
+
y="9"
|
|
8499
|
+
width="13"
|
|
8500
|
+
height="13"
|
|
8501
|
+
rx="2"
|
|
8502
|
+
/>
|
|
8503
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
|
|
8504
|
+
</svg>
|
|
8505
|
+
`}
|
|
8506
|
+
</span>
|
|
8507
|
+
</button>
|
|
8508
|
+
${this._toolDetailOutputOpen
|
|
8509
|
+
? b `<pre class="tool-detail__code">${this._formatToolJson(this._toolDetail.result?.data?.toolResultString) || '(no output yet)'}</pre>`
|
|
8510
|
+
: A}
|
|
8511
|
+
</div>
|
|
8512
|
+
</div>
|
|
8513
|
+
`;
|
|
8514
|
+
}
|
|
8205
8515
|
/** The Debug view's body — telemetry scopes and the per-iteration table. */
|
|
8206
8516
|
_renderDebugContent() {
|
|
8207
8517
|
return b `
|
|
@@ -8563,8 +8873,17 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
8563
8873
|
catch {
|
|
8564
8874
|
formatted = String(result.toolResultString);
|
|
8565
8875
|
}
|
|
8876
|
+
// Cap the inline preview by BOTH lines and characters. Line-only
|
|
8877
|
+
// truncation blows up on results whose first line is huge (e.g. a
|
|
8878
|
+
// minified-JSON blob or a stashed-response marker with a 30k-char
|
|
8879
|
+
// opening line) — 3 lines then still dumps tens of thousands of
|
|
8880
|
+
// chars into the transcript. Char-cap first (content-blind, like
|
|
8881
|
+
// the backend chokepoint), then keep at most 3 lines of that.
|
|
8566
8882
|
const lines = formatted.split('\n');
|
|
8567
8883
|
resultPreview = lines.slice(0, 3).join('\n');
|
|
8884
|
+
if (resultPreview.length > 200) {
|
|
8885
|
+
resultPreview = `${resultPreview.slice(0, 200)}…`;
|
|
8886
|
+
}
|
|
8568
8887
|
resultRemainder = Math.max(0, lines.length - 3);
|
|
8569
8888
|
}
|
|
8570
8889
|
}
|
|
@@ -8593,24 +8912,32 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
8593
8912
|
})}>
|
|
8594
8913
|
${msg.type === 'tool_use' ? b `
|
|
8595
8914
|
<div class="tool-activity-block">
|
|
8596
|
-
<
|
|
8915
|
+
<button
|
|
8916
|
+
type="button"
|
|
8917
|
+
class=${e({
|
|
8597
8918
|
'tool-activity': true,
|
|
8598
8919
|
'tool-activity--error': result?.toolResultStatus === 'error',
|
|
8599
|
-
})}
|
|
8920
|
+
})}
|
|
8921
|
+
@click=${() => this._openToolDetail(msg)}
|
|
8922
|
+
>
|
|
8600
8923
|
<span class="tool-activity__chevron">›</span>
|
|
8601
8924
|
<span class="tool-activity__label">${msg.data?.displayName || msg.data?.toolName || 'Tool'}</span>
|
|
8602
8925
|
${inputSummary ? b `<span class="tool-activity__input">(${inputSummary})</span>` : A}
|
|
8603
|
-
</
|
|
8926
|
+
</button>
|
|
8604
8927
|
${this._showToolInputs && result?.toolResultString ? b `
|
|
8605
|
-
<
|
|
8928
|
+
<button
|
|
8929
|
+
type="button"
|
|
8930
|
+
class=${e({
|
|
8606
8931
|
'tool-activity__result': true,
|
|
8607
8932
|
'tool-activity__result--error': result.toolResultStatus === 'error',
|
|
8608
|
-
})}
|
|
8933
|
+
})}
|
|
8934
|
+
@click=${() => this._openToolDetail(msg)}
|
|
8935
|
+
>
|
|
8609
8936
|
<span class="tool-activity__connector">⎿</span>
|
|
8610
8937
|
<pre class="tool-activity__result-body">${resultPreview}${resultRemainder > 0
|
|
8611
8938
|
? b `\n<span class="tool-activity__more">… +${resultRemainder} lines</span>`
|
|
8612
8939
|
: A}</pre>
|
|
8613
|
-
</
|
|
8940
|
+
</button>
|
|
8614
8941
|
` : A}
|
|
8615
8942
|
</div>
|
|
8616
8943
|
` : A}
|
|
@@ -9215,6 +9542,102 @@ KRChatbot.styles = i$6 `
|
|
|
9215
9542
|
padding: 6px 0;
|
|
9216
9543
|
}
|
|
9217
9544
|
|
|
9545
|
+
/* Tool detail view — the full input/output for one tool call. */
|
|
9546
|
+
.tool-detail {
|
|
9547
|
+
display: flex;
|
|
9548
|
+
flex-direction: column;
|
|
9549
|
+
gap: 24px;
|
|
9550
|
+
padding: 16px 20px;
|
|
9551
|
+
}
|
|
9552
|
+
|
|
9553
|
+
.tool-detail__section {
|
|
9554
|
+
display: flex;
|
|
9555
|
+
flex-direction: column;
|
|
9556
|
+
gap: 8px;
|
|
9557
|
+
min-width: 0;
|
|
9558
|
+
}
|
|
9559
|
+
|
|
9560
|
+
/* Clickable section header — toggles the code block below. Button chrome is
|
|
9561
|
+
stripped so it reads as a heading row. */
|
|
9562
|
+
.tool-detail__section-head {
|
|
9563
|
+
display: flex;
|
|
9564
|
+
align-items: center;
|
|
9565
|
+
gap: 8px;
|
|
9566
|
+
appearance: none;
|
|
9567
|
+
background: none;
|
|
9568
|
+
border: none;
|
|
9569
|
+
width: 100%;
|
|
9570
|
+
font-family: inherit;
|
|
9571
|
+
text-align: left;
|
|
9572
|
+
cursor: pointer;
|
|
9573
|
+
border-radius: 4px;
|
|
9574
|
+
}
|
|
9575
|
+
|
|
9576
|
+
.tool-detail__section-head:focus-visible {
|
|
9577
|
+
outline: 2px solid var(--kr-chatbot-primary);
|
|
9578
|
+
outline-offset: 2px;
|
|
9579
|
+
}
|
|
9580
|
+
|
|
9581
|
+
/* Disclosure caret — the same "›" used on tool lines; rotates down when open. */
|
|
9582
|
+
.tool-detail__caret {
|
|
9583
|
+
flex-shrink: 0;
|
|
9584
|
+
font-size: 16px;
|
|
9585
|
+
color: rgba(0, 0, 0, 0.55);
|
|
9586
|
+
transition: transform 0.15s ease;
|
|
9587
|
+
}
|
|
9588
|
+
|
|
9589
|
+
.tool-detail__caret--open {
|
|
9590
|
+
transform: rotate(90deg);
|
|
9591
|
+
}
|
|
9592
|
+
|
|
9593
|
+
.tool-detail__section-title {
|
|
9594
|
+
font-size: 12px;
|
|
9595
|
+
font-weight: 700;
|
|
9596
|
+
text-transform: uppercase;
|
|
9597
|
+
letter-spacing: 0.06em;
|
|
9598
|
+
color: #000000;
|
|
9599
|
+
}
|
|
9600
|
+
|
|
9601
|
+
/* Copy icon-button — same treatment as the per-message copy button. */
|
|
9602
|
+
.tool-detail__copy {
|
|
9603
|
+
margin-left: auto;
|
|
9604
|
+
display: inline-flex;
|
|
9605
|
+
align-items: center;
|
|
9606
|
+
justify-content: center;
|
|
9607
|
+
width: 26px;
|
|
9608
|
+
height: 26px;
|
|
9609
|
+
padding: 0;
|
|
9610
|
+
background: none;
|
|
9611
|
+
border: none;
|
|
9612
|
+
border-radius: 6px;
|
|
9613
|
+
color: #000000;
|
|
9614
|
+
cursor: pointer;
|
|
9615
|
+
transition: background-color 0.15s, color 0.15s;
|
|
9616
|
+
}
|
|
9617
|
+
|
|
9618
|
+
.tool-detail__copy:hover {
|
|
9619
|
+
background: rgba(0, 0, 0, 0.06);
|
|
9620
|
+
}
|
|
9621
|
+
|
|
9622
|
+
.tool-detail__copy svg {
|
|
9623
|
+
width: 14px;
|
|
9624
|
+
height: 14px;
|
|
9625
|
+
}
|
|
9626
|
+
|
|
9627
|
+
/* The code block — pretty-printed JSON, shown in full (no inner scroll). The
|
|
9628
|
+
drawer body is the only scroll container, so long inputs/outputs extend the
|
|
9629
|
+
page and you scroll the panel, not a nested box. */
|
|
9630
|
+
.tool-detail__code {
|
|
9631
|
+
margin: 0;
|
|
9632
|
+
padding: 0 18px;
|
|
9633
|
+
font-family: 'SF Mono', 'Fira Code', Monaco, monospace;
|
|
9634
|
+
font-size: 12px;
|
|
9635
|
+
line-height: 1.5;
|
|
9636
|
+
color: #000000;
|
|
9637
|
+
white-space: pre-wrap;
|
|
9638
|
+
word-break: break-word;
|
|
9639
|
+
}
|
|
9640
|
+
|
|
9218
9641
|
/* Messages */
|
|
9219
9642
|
/* Full-width scroll container — keeps the scrollbar at the panel edge. */
|
|
9220
9643
|
.messages {
|
|
@@ -9311,6 +9734,9 @@ KRChatbot.styles = i$6 `
|
|
|
9311
9734
|
/* Tool-activity line — "the assistant ran X" row in the transcript. Same text
|
|
9312
9735
|
style as any other message (black, 14px); a leading › chevron marks it as a
|
|
9313
9736
|
step (in the same text style, not an icon). */
|
|
9737
|
+
/* The tool-activity line and its result preview are <button>s (they open the
|
|
9738
|
+
tool-detail drawer on click) — strip the native button chrome so they read
|
|
9739
|
+
as plain transcript text, then re-add the layout. */
|
|
9314
9740
|
.tool-activity {
|
|
9315
9741
|
align-self: flex-start;
|
|
9316
9742
|
display: flex;
|
|
@@ -9320,6 +9746,22 @@ KRChatbot.styles = i$6 `
|
|
|
9320
9746
|
color: #000000;
|
|
9321
9747
|
/* Keep the chevron + name + input on a single line; input truncates if long. */
|
|
9322
9748
|
white-space: nowrap;
|
|
9749
|
+
/* Button reset */
|
|
9750
|
+
appearance: none;
|
|
9751
|
+
background: none;
|
|
9752
|
+
border: none;
|
|
9753
|
+
margin: 0;
|
|
9754
|
+
padding: 2px 4px;
|
|
9755
|
+
font-family: inherit;
|
|
9756
|
+
text-align: left;
|
|
9757
|
+
cursor: pointer;
|
|
9758
|
+
border-radius: 4px;
|
|
9759
|
+
max-width: 100%;
|
|
9760
|
+
}
|
|
9761
|
+
|
|
9762
|
+
.tool-activity:focus-visible {
|
|
9763
|
+
outline: 2px solid var(--kr-chatbot-primary);
|
|
9764
|
+
outline-offset: 1px;
|
|
9323
9765
|
}
|
|
9324
9766
|
|
|
9325
9767
|
.tool-activity--error {
|
|
@@ -9355,6 +9797,16 @@ KRChatbot.styles = i$6 `
|
|
|
9355
9797
|
gap: 4px;
|
|
9356
9798
|
}
|
|
9357
9799
|
|
|
9800
|
+
/* One hover for the whole tool block: hovering anywhere over the header or its
|
|
9801
|
+
result underlines the tool name, input, and result together as a single
|
|
9802
|
+
link, rather than lighting up header and result separately. */
|
|
9803
|
+
.tool-activity-block:hover .tool-activity__label,
|
|
9804
|
+
.tool-activity-block:hover .tool-activity__input,
|
|
9805
|
+
.tool-activity-block:hover .tool-activity__result-body {
|
|
9806
|
+
text-decoration: underline;
|
|
9807
|
+
text-decoration-color: rgba(0, 0, 0, 0.25);
|
|
9808
|
+
}
|
|
9809
|
+
|
|
9358
9810
|
/* The result block indented under the activity line with a ⎿ tree connector,
|
|
9359
9811
|
like Claude CLI's tool output preview. Uses the normal message text style
|
|
9360
9812
|
(14px, black) — only the ⎿ connector is muted. */
|
|
@@ -9370,6 +9822,20 @@ KRChatbot.styles = i$6 `
|
|
|
9370
9822
|
margin-left: 6px;
|
|
9371
9823
|
font-size: 14px;
|
|
9372
9824
|
color: #000000;
|
|
9825
|
+
/* Button reset — this preview row is also a click target for the detail view. */
|
|
9826
|
+
appearance: none;
|
|
9827
|
+
background: none;
|
|
9828
|
+
border: none;
|
|
9829
|
+
padding: 0;
|
|
9830
|
+
font-family: inherit;
|
|
9831
|
+
text-align: left;
|
|
9832
|
+
cursor: pointer;
|
|
9833
|
+
}
|
|
9834
|
+
|
|
9835
|
+
.tool-activity__result:focus-visible {
|
|
9836
|
+
outline: 2px solid var(--kr-chatbot-primary);
|
|
9837
|
+
outline-offset: 1px;
|
|
9838
|
+
border-radius: 4px;
|
|
9373
9839
|
}
|
|
9374
9840
|
|
|
9375
9841
|
.tool-activity__result--error {
|
|
@@ -10835,6 +11301,18 @@ __decorate([
|
|
|
10835
11301
|
__decorate([
|
|
10836
11302
|
r()
|
|
10837
11303
|
], KRChatbot.prototype, "_drawerView", void 0);
|
|
11304
|
+
__decorate([
|
|
11305
|
+
r()
|
|
11306
|
+
], KRChatbot.prototype, "_toolDetail", void 0);
|
|
11307
|
+
__decorate([
|
|
11308
|
+
r()
|
|
11309
|
+
], KRChatbot.prototype, "_toolDetailCopied", void 0);
|
|
11310
|
+
__decorate([
|
|
11311
|
+
r()
|
|
11312
|
+
], KRChatbot.prototype, "_toolDetailInputOpen", void 0);
|
|
11313
|
+
__decorate([
|
|
11314
|
+
r()
|
|
11315
|
+
], KRChatbot.prototype, "_toolDetailOutputOpen", void 0);
|
|
10838
11316
|
__decorate([
|
|
10839
11317
|
r()
|
|
10840
11318
|
], KRChatbot.prototype, "_drawerWidth", void 0);
|
|
@@ -10916,6 +11394,9 @@ __decorate([
|
|
|
10916
11394
|
__decorate([
|
|
10917
11395
|
e$3('.skill-menu')
|
|
10918
11396
|
], KRChatbot.prototype, "_skillMenuEl", void 0);
|
|
11397
|
+
__decorate([
|
|
11398
|
+
e$3('.drawer__body')
|
|
11399
|
+
], KRChatbot.prototype, "_drawerBodyEl", void 0);
|
|
10919
11400
|
KRChatbot = __decorate([
|
|
10920
11401
|
t$2('kr-chatbot')
|
|
10921
11402
|
], KRChatbot);
|