@kodaris/krubble-app-components 1.0.73 → 1.0.75

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 CHANGED
@@ -56,17 +56,18 @@ export interface KRChatbotMessage {
56
56
  }
57
57
  /**
58
58
  * A skill the user can invoke from the composer. Selecting one inserts
59
- * `/name ` into the message body — there is no persistent skill state.
59
+ * `/code ` into the message body — there is no persistent skill state.
60
+ *
61
+ * Field names mirror the backend AI skill document (the `_source` of an
62
+ * `/aiskills/search` hit) so loaded skills pass through without remapping.
60
63
  */
61
64
  export interface KRChatbotSkill {
62
- /** Slash name inserted into the message (e.g. `invoice-auditor`). */
65
+ /** Skill code — the slash name inserted into the message (e.g. `invoice-auditor`). */
66
+ code: string;
67
+ /** Human-readable name shown in the menu and browse dialog. */
63
68
  name: string;
64
- /** Human-readable label shown in the menu and browse dialog. */
65
- label: string;
66
69
  /** Short description shown in the browse dialog cards. */
67
70
  description?: string;
68
- /** Which catalog the skill belongs to, for the browse dialog tabs. */
69
- source?: 'org' | 'kodaris';
70
71
  }
71
72
  /**
72
73
  * Callback function type for sending messages.
@@ -136,6 +137,11 @@ export declare class KRChatbot extends LitElement {
136
137
  private _dragDepth;
137
138
  /** Monotonic id source for pending attachments. */
138
139
  private _pendingSeq;
140
+ /**
141
+ * Request-id guard for skill searches — bumped on each search so out-of-order
142
+ * responses are dropped (mirrors the kr-combo-box `_requestId` pattern).
143
+ */
144
+ private _skillRequestId;
139
145
  /**
140
146
  * Callback function for sending messages. Receives the user's message and
141
147
  * current conversation history. Must return a Response with a streaming SSE body.
@@ -173,12 +179,6 @@ export declare class KRChatbot extends LitElement {
173
179
  * Input placeholder text.
174
180
  */
175
181
  placeholder: string;
176
- /**
177
- * Skills the user can invoke by typing `/` in the composer. Selecting one
178
- * inserts `/name ` into the message. The `/` menu shows the first 15 (filtered
179
- * as the user types); "Browse all skills" opens a dialog with the full list.
180
- */
181
- skills: KRChatbotSkill[];
182
182
  /**
183
183
  * Whether the chat panel is open. Only relevant in floating mode.
184
184
  */
@@ -209,17 +209,25 @@ export declare class KRChatbot extends LitElement {
209
209
  private _isDraggingFile;
210
210
  /** Whether the `/` skill menu is open above the composer. */
211
211
  private _skillMenuOpened;
212
- /** Current `/` query (text after the slash), used to filter the skill menu. */
212
+ /** Current `/` query (text after the slash), sent to `_searchSkills`. */
213
213
  private _skillQuery;
214
+ /**
215
+ * Latest skill search results. Shared by the `/` menu and the browse dialog —
216
+ * they're mutually exclusive (opening browse closes the menu), so one buffer.
217
+ */
218
+ private _skillResults;
214
219
  /** Highlighted item in the skill menu for keyboard navigation (-1 = none). */
215
220
  private _skillHighlighted;
216
221
  /** Index of the message whose copy button just flashed "Copied" (-1 = none). */
217
222
  private _copiedIndex;
218
223
  /** Whether the "Browse all skills" dialog is open. */
219
224
  private _skillBrowseOpened;
220
- /** Active tab in the browse dialog. */
225
+ /**
226
+ * Active tab in the browse dialog. `org` lists this org's skills (searched via
227
+ * `_searchSkills`); `kodaris` is the shared global catalog, added later.
228
+ */
221
229
  private _skillBrowseSource;
222
- /** Search text in the browse dialog. */
230
+ /** Search text in the browse dialog, sent to `_searchSkills`. */
223
231
  private _skillBrowseQuery;
224
232
  private _panelEl;
225
233
  private _messagesEl;
@@ -275,11 +283,22 @@ export declare class KRChatbot extends LitElement {
275
283
  private _handleKeyDown;
276
284
  /** Run the skill-menu item at the given flat index (0/1 = actions, then skills). */
277
285
  private _activateSkillMenuItem;
278
- /** Skills matching the current `/` query, capped at the first 15. */
279
- private _filteredSkills;
286
+ /**
287
+ * Search the Kodaris AI skills index and store the results in `_skillResults`.
288
+ * The `/` menu and the browse dialog both call this; results are shared since
289
+ * the two are never open at once. Mirrors the backend's own skill search (BM25
290
+ * over name^3/description^2/instructions, active-only) so the menu ranks skills
291
+ * the way the model does. An empty query uses match_all — multi_match with an
292
+ * empty string matches nothing, so the "show everything" case needs it.
293
+ *
294
+ * Follows the kr-combo-box `_fetch` pattern: a request-id guard drops responses
295
+ * that arrive out of order. `/aiskills/search` returns a raw OpenSearch response,
296
+ * so we lift each hit's `_source` (already in KRChatbotSkill shape) out.
297
+ */
298
+ private _searchSkills;
280
299
  /** The `+` button toggles the skill/attachment menu open (showing all skills). */
281
300
  private _handlePlusClick;
282
- /** Insert `/name ` into the composer and focus it, ready for the message. */
301
+ /** Insert `/code ` into the composer and focus it, ready for the message. */
283
302
  private _handleSkillSelect;
284
303
  /** Copy a message's text to the clipboard and briefly flash "Copied". */
285
304
  private _handleCopyMessage;
@@ -287,8 +306,6 @@ export declare class KRChatbot extends LitElement {
287
306
  private _handleSkillBrowseClose;
288
307
  private _handleSkillBrowseSearch;
289
308
  private _handleSkillBrowseTabChange;
290
- /** Skills for the browse dialog's active tab, filtered by its search box. */
291
- private _browseSkills;
292
309
  private _openFilePicker;
293
310
  private _handleFileInputChange;
294
311
  private _handlePaste;
@@ -316,11 +333,12 @@ export declare class KRChatbot extends LitElement {
316
333
  private _renderSkillMenu;
317
334
  /** The "Browse all skills" dialog — a searchable grid of Org / Kodaris cards. */
318
335
  private _renderSkillBrowse;
319
- /** The card grid for the browse dialog's active tab. */
336
+ /** The card grid of this org's skill search results for the browse dialog. */
320
337
  private _renderSkillGrid;
321
338
  /**
322
- * Render a user message, highlighting a leading `/skill-name` token when it
323
- * matches a known skill (like the way Claude highlights slash commands).
339
+ * Render a user message, highlighting a leading `/skill-code` token (like the
340
+ * way Claude highlights slash commands). The composer only inserts valid skill
341
+ * codes, so any leading slash token is treated as one.
324
342
  */
325
343
  private _renderUserContent;
326
344
  render(): import("lit-html").TemplateResult<1>;
@@ -1 +1 @@
1
- {"version":3,"file":"chatbot.d.ts","sourceRoot":"","sources":["../src/chatbot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chatbot.d.ts","sourceRoot":"","sources":["../src/chatbot.ts"],"names":[],"mappings":"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"}
package/dist/chatbot.js CHANGED
@@ -75,6 +75,11 @@ let KRChatbot = class KRChatbot extends LitElement {
75
75
  this._dragDepth = 0;
76
76
  /** Monotonic id source for pending attachments. */
77
77
  this._pendingSeq = 0;
78
+ /**
79
+ * Request-id guard for skill searches — bumped on each search so out-of-order
80
+ * responses are dropped (mirrors the kr-combo-box `_requestId` pattern).
81
+ */
82
+ this._skillRequestId = 0;
78
83
  // --- @property (public API) ---
79
84
  /**
80
85
  * Callback function for sending messages. Receives the user's message and
@@ -113,12 +118,6 @@ let KRChatbot = class KRChatbot extends LitElement {
113
118
  * Input placeholder text.
114
119
  */
115
120
  this.placeholder = 'Type a message...';
116
- /**
117
- * Skills the user can invoke by typing `/` in the composer. Selecting one
118
- * inserts `/name ` into the message. The `/` menu shows the first 15 (filtered
119
- * as the user types); "Browse all skills" opens a dialog with the full list.
120
- */
121
- this.skills = [];
122
121
  /**
123
122
  * Whether the chat panel is open. Only relevant in floating mode.
124
123
  */
@@ -150,17 +149,25 @@ let KRChatbot = class KRChatbot extends LitElement {
150
149
  this._isDraggingFile = false;
151
150
  /** Whether the `/` skill menu is open above the composer. */
152
151
  this._skillMenuOpened = false;
153
- /** Current `/` query (text after the slash), used to filter the skill menu. */
152
+ /** Current `/` query (text after the slash), sent to `_searchSkills`. */
154
153
  this._skillQuery = '';
154
+ /**
155
+ * Latest skill search results. Shared by the `/` menu and the browse dialog —
156
+ * they're mutually exclusive (opening browse closes the menu), so one buffer.
157
+ */
158
+ this._skillResults = [];
155
159
  /** Highlighted item in the skill menu for keyboard navigation (-1 = none). */
156
160
  this._skillHighlighted = 0;
157
161
  /** Index of the message whose copy button just flashed "Copied" (-1 = none). */
158
162
  this._copiedIndex = -1;
159
163
  /** Whether the "Browse all skills" dialog is open. */
160
164
  this._skillBrowseOpened = false;
161
- /** Active tab in the browse dialog. */
165
+ /**
166
+ * Active tab in the browse dialog. `org` lists this org's skills (searched via
167
+ * `_searchSkills`); `kodaris` is the shared global catalog, added later.
168
+ */
162
169
  this._skillBrowseSource = 'org';
163
- /** Search text in the browse dialog. */
170
+ /** Search text in the browse dialog, sent to `_searchSkills`. */
164
171
  this._skillBrowseQuery = '';
165
172
  this._handleMouseMove = (e) => {
166
173
  if (this._isDragging) {
@@ -503,12 +510,14 @@ let KRChatbot = class KRChatbot extends LitElement {
503
510
  textarea.style.height = 'auto';
504
511
  textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px';
505
512
  // Open the skill menu while the message is a `/` command being typed (a
506
- // leading slash with no space yet). The text after the slash filters it.
513
+ // leading slash with no space yet). The text after the slash is the search
514
+ // query, run server-side via `_searchSkills`.
507
515
  const slashMatch = this._inputValue.match(/^\/(\S*)$/);
508
- if (slashMatch && this.skills.length) {
516
+ if (slashMatch) {
509
517
  this._skillMenuOpened = true;
510
518
  this._skillQuery = slashMatch[1];
511
519
  this._skillHighlighted = 0;
520
+ this._searchSkills(this._skillQuery);
512
521
  }
513
522
  else {
514
523
  this._skillMenuOpened = false;
@@ -519,7 +528,7 @@ let KRChatbot = class KRChatbot extends LitElement {
519
528
  // top actions (Attach Files, Browse All Skills) are index 0 and 1, then the
520
529
  // filtered skills follow — all navigable as one list.
521
530
  if (this._skillMenuOpened) {
522
- const count = 2 + this._filteredSkills().length;
531
+ const count = 2 + this._skillResults.length;
523
532
  if (e.key === 'ArrowDown') {
524
533
  e.preventDefault();
525
534
  this._skillHighlighted = (this._skillHighlighted + 1) % count;
@@ -556,19 +565,64 @@ let KRChatbot = class KRChatbot extends LitElement {
556
565
  this._handleSkillBrowseOpen();
557
566
  return;
558
567
  }
559
- const skill = this._filteredSkills()[index - 2];
568
+ const skill = this._skillResults[index - 2];
560
569
  if (skill) {
561
570
  this._handleSkillSelect(skill);
562
571
  }
563
572
  }
564
573
  // --- Skills ---
565
- /** Skills matching the current `/` query, capped at the first 15. */
566
- _filteredSkills() {
567
- const query = this._skillQuery.toLowerCase();
568
- return this.skills
569
- .filter((skill) => skill.name.toLowerCase().includes(query) ||
570
- skill.label.toLowerCase().includes(query))
571
- .slice(0, 15);
574
+ /**
575
+ * Search the Kodaris AI skills index and store the results in `_skillResults`.
576
+ * The `/` menu and the browse dialog both call this; results are shared since
577
+ * the two are never open at once. Mirrors the backend's own skill search (BM25
578
+ * over name^3/description^2/instructions, active-only) so the menu ranks skills
579
+ * the way the model does. An empty query uses match_all — multi_match with an
580
+ * empty string matches nothing, so the "show everything" case needs it.
581
+ *
582
+ * Follows the kr-combo-box `_fetch` pattern: a request-id guard drops responses
583
+ * that arrive out of order. `/aiskills/search` returns a raw OpenSearch response,
584
+ * so we lift each hit's `_source` (already in KRChatbotSkill shape) out.
585
+ */
586
+ _searchSkills(query) {
587
+ this._skillRequestId++;
588
+ const requestId = this._skillRequestId;
589
+ const trimmed = query.trim();
590
+ // multi_match with an empty string matches nothing, so an empty query falls
591
+ // back to match_all to show everything.
592
+ let must = { match_all: {} };
593
+ if (trimmed) {
594
+ must = {
595
+ multi_match: {
596
+ query: trimmed,
597
+ fields: ['name^3', 'description^2', 'instructions'],
598
+ type: 'best_fields',
599
+ },
600
+ };
601
+ }
602
+ KRHttp.fetch({
603
+ url: '/api/system/opensearch/aiskills/search',
604
+ method: 'POST',
605
+ body: {
606
+ size: 100,
607
+ query: {
608
+ bool: {
609
+ must: [must],
610
+ filter: [{ term: { active: true } }],
611
+ },
612
+ },
613
+ },
614
+ })
615
+ .then((r) => r.json())
616
+ .then((res) => {
617
+ // Ignore a stale response superseded by a newer search.
618
+ if (requestId !== this._skillRequestId) {
619
+ return;
620
+ }
621
+ this._skillResults = (res?.data?.hits?.hits || []).map((hit) => hit._source);
622
+ })
623
+ .catch((error) => {
624
+ console.error('kr-chatbot: skill search failed', error);
625
+ });
572
626
  }
573
627
  /** The `+` button toggles the skill/attachment menu open (showing all skills). */
574
628
  _handlePlusClick() {
@@ -579,10 +633,11 @@ let KRChatbot = class KRChatbot extends LitElement {
579
633
  this._skillQuery = '';
580
634
  this._skillHighlighted = 0;
581
635
  this._skillMenuOpened = true;
636
+ this._searchSkills('');
582
637
  }
583
- /** Insert `/name ` into the composer and focus it, ready for the message. */
638
+ /** Insert `/code ` into the composer and focus it, ready for the message. */
584
639
  _handleSkillSelect(skill) {
585
- this._inputValue = `/${skill.name} `;
640
+ this._inputValue = `/${skill.code} `;
586
641
  this._skillMenuOpened = false;
587
642
  this._skillBrowseOpened = false;
588
643
  this._inputEl?.focus();
@@ -602,29 +657,18 @@ let KRChatbot = class KRChatbot extends LitElement {
602
657
  this._skillMenuOpened = false;
603
658
  this._skillBrowseQuery = '';
604
659
  this._skillBrowseOpened = true;
660
+ this._searchSkills('');
605
661
  }
606
662
  _handleSkillBrowseClose() {
607
663
  this._skillBrowseOpened = false;
608
664
  }
609
665
  _handleSkillBrowseSearch(e) {
610
666
  this._skillBrowseQuery = e.target.value;
667
+ this._searchSkills(this._skillBrowseQuery);
611
668
  }
612
669
  _handleSkillBrowseTabChange(e) {
613
670
  this._skillBrowseSource = e.detail.activeTabId;
614
671
  }
615
- /** Skills for the browse dialog's active tab, filtered by its search box. */
616
- _browseSkills() {
617
- const query = this._skillBrowseQuery.toLowerCase();
618
- return this.skills.filter((skill) => {
619
- const source = skill.source || 'org';
620
- if (source !== this._skillBrowseSource) {
621
- return false;
622
- }
623
- return skill.name.toLowerCase().includes(query) ||
624
- skill.label.toLowerCase().includes(query) ||
625
- (skill.description || '').toLowerCase().includes(query);
626
- });
627
- }
628
672
  // --- Attachments ---
629
673
  _openFilePicker() {
630
674
  this._fileInputEl?.click();
@@ -984,7 +1028,7 @@ let KRChatbot = class KRChatbot extends LitElement {
984
1028
  // --- Render ---
985
1029
  /** The `/` skill menu shown above the composer while typing a slash command. */
986
1030
  _renderSkillMenu() {
987
- const skills = this._filteredSkills();
1031
+ const skills = this._skillResults;
988
1032
  return html `
989
1033
  <div class="skill-menu">
990
1034
  <div class="skill-menu__actions">
@@ -1018,7 +1062,7 @@ let KRChatbot = class KRChatbot extends LitElement {
1018
1062
  })}
1019
1063
  @click=${() => this._handleSkillSelect(skill)}
1020
1064
  >
1021
- <span class="skill-menu__name">${skill.label}</span>
1065
+ <span class="skill-menu__name">${skill.name}</span>
1022
1066
  ${skill.description ? html `
1023
1067
  <span class="skill-menu__desc">${skill.description}</span>
1024
1068
  ` : nothing}
@@ -1026,9 +1070,7 @@ let KRChatbot = class KRChatbot extends LitElement {
1026
1070
  </li>
1027
1071
  `)}
1028
1072
  </ul>
1029
- ` : html `
1030
- <div class="skill-menu__empty">No matching skills</div>
1031
- `}
1073
+ ` : nothing}
1032
1074
  </div>
1033
1075
  `;
1034
1076
  }
@@ -1055,18 +1097,20 @@ let KRChatbot = class KRChatbot extends LitElement {
1055
1097
  ${this._renderSkillGrid()}
1056
1098
  </kr-tab>
1057
1099
  <kr-tab id="kodaris" label="Kodaris">
1058
- ${this._renderSkillGrid()}
1100
+ <div class="skill-browse__empty">
1101
+ Shared Kodaris skills are coming soon.
1102
+ </div>
1059
1103
  </kr-tab>
1060
1104
  </kr-tab-group>
1061
1105
  </div>
1062
1106
  </kr-dialog>
1063
1107
  `;
1064
1108
  }
1065
- /** The card grid for the browse dialog's active tab. */
1109
+ /** The card grid of this org's skill search results for the browse dialog. */
1066
1110
  _renderSkillGrid() {
1067
- const skills = this._browseSkills();
1111
+ const skills = this._skillResults;
1068
1112
  if (!skills.length) {
1069
- return html `<div class="skill-browse__empty">No matching skills</div>`;
1113
+ return nothing;
1070
1114
  }
1071
1115
  return html `
1072
1116
  <div class="skill-browse__grid">
@@ -1075,7 +1119,7 @@ let KRChatbot = class KRChatbot extends LitElement {
1075
1119
  class="skill-card"
1076
1120
  @click=${() => this._handleSkillSelect(skill)}
1077
1121
  >
1078
- <span class="skill-card__name">${skill.label}</span>
1122
+ <span class="skill-card__name">${skill.name}</span>
1079
1123
  ${skill.description ? html `
1080
1124
  <span class="skill-card__desc">${skill.description}</span>
1081
1125
  ` : nothing}
@@ -1085,12 +1129,13 @@ let KRChatbot = class KRChatbot extends LitElement {
1085
1129
  `;
1086
1130
  }
1087
1131
  /**
1088
- * Render a user message, highlighting a leading `/skill-name` token when it
1089
- * matches a known skill (like the way Claude highlights slash commands).
1132
+ * Render a user message, highlighting a leading `/skill-code` token (like the
1133
+ * way Claude highlights slash commands). The composer only inserts valid skill
1134
+ * codes, so any leading slash token is treated as one.
1090
1135
  */
1091
1136
  _renderUserContent(content) {
1092
1137
  const match = content.match(/^\/(\S+)(\s[\s\S]*)?$/);
1093
- if (match && this.skills.some((skill) => skill.name === match[1])) {
1138
+ if (match) {
1094
1139
  return html `<span class="message-skill">/${match[1]}</span>${match[2] || ''}`;
1095
1140
  }
1096
1141
  return content;
@@ -2196,12 +2241,6 @@ KRChatbot.styles = css `
2196
2241
  white-space: nowrap;
2197
2242
  }
2198
2243
 
2199
- .skill-menu__empty {
2200
- padding: 16px;
2201
- text-align: center;
2202
- color: #000000;
2203
- }
2204
-
2205
2244
  .skill-menu__actions {
2206
2245
  display: flex;
2207
2246
  flex-direction: column;
@@ -2292,6 +2331,12 @@ KRChatbot.styles = css `
2292
2331
  .skill-card__desc {
2293
2332
  font-size: 12px;
2294
2333
  color: #000000;
2334
+ /* Clamp to 3 lines so a long description doesn't make one card tower over
2335
+ its row-mates in the grid. */
2336
+ display: -webkit-box;
2337
+ -webkit-line-clamp: 3;
2338
+ -webkit-box-orient: vertical;
2339
+ overflow: hidden;
2295
2340
  }
2296
2341
 
2297
2342
  .skill-browse__empty {
@@ -2400,9 +2445,6 @@ __decorate([
2400
2445
  __decorate([
2401
2446
  property({ type: String })
2402
2447
  ], KRChatbot.prototype, "placeholder", void 0);
2403
- __decorate([
2404
- property({ attribute: false })
2405
- ], KRChatbot.prototype, "skills", void 0);
2406
2448
  __decorate([
2407
2449
  property({
2408
2450
  type: Boolean,
@@ -2443,6 +2485,9 @@ __decorate([
2443
2485
  __decorate([
2444
2486
  state()
2445
2487
  ], KRChatbot.prototype, "_skillQuery", void 0);
2488
+ __decorate([
2489
+ state()
2490
+ ], KRChatbot.prototype, "_skillResults", void 0);
2446
2491
  __decorate([
2447
2492
  state()
2448
2493
  ], KRChatbot.prototype, "_skillHighlighted", void 0);