@eclipse-docks/extension-ai-system 0.8.2 → 0.8.4

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/api.js CHANGED
@@ -1,4 +1,4 @@
1
- import { D as AI_VIEW_NAME, E as AI_SETTINGS_KEY, O as OPEN_AI_SETTINGS_COMMAND, S as parseModelIds, T as AI_SETTINGS_EDITOR_ID, a as listSkillContributions, b as defaultProvidersSettings, c as resolveSkillBody, d as parseSkillMarkdown, i as SYSTEM_SKILLS, k as TOPIC, l as isSkillContribution, n as CognitiveRuntime, o as registerSkillMarkdown, r as cognitiveRuntime, s as resolveSkill, t as registerSkillCommands, u as formatSkillForPrompt, v as OpenAICompatibleProvider, w as loadModelsCatalog, x as listConfiguredModelIds, y as fetchOpenAICompatibleModels } from "./runtime-B0IHjzQO.js";
1
+ import { D as AI_VIEW_NAME, E as AI_SETTINGS_KEY, O as OPEN_AI_SETTINGS_COMMAND, S as parseModelIds, T as AI_SETTINGS_EDITOR_ID, a as listSkillContributions, b as defaultProvidersSettings, c as resolveSkillBody, d as parseSkillMarkdown, i as SYSTEM_SKILLS, k as TOPIC, l as isSkillContribution, n as CognitiveRuntime, o as registerSkillMarkdown, r as cognitiveRuntime, s as resolveSkill, t as registerSkillCommands, u as formatSkillForPrompt, v as OpenAICompatibleProvider, w as loadModelsCatalog, x as listConfiguredModelIds, y as fetchOpenAICompatibleModels } from "./runtime-DVzLyx8h.js";
2
2
  //#region src/runtime/skills-select.ts
3
3
  /**
4
4
  * Catalog-only prompt section. The model loads full skill bodies via skills.load.
@@ -1,4 +1,4 @@
1
- import { C as detectEffortCapability, D as AI_VIEW_NAME, E as AI_SETTINGS_KEY, O as OPEN_AI_SETTINGS_COMMAND, S as parseModelIds, T as AI_SETTINGS_EDITOR_ID, _ as readPromptAttachmentFromFile, b as defaultProvidersSettings, f as estimateSessionContextUsage, g as ATTACHMENT_FILE_ACCEPT, h as formatTokenCount, k as TOPIC, m as formatContextPercent, p as formatBucketDetail, r as cognitiveRuntime, t as registerSkillCommands, y as fetchOpenAICompatibleModels } from "./runtime-B0IHjzQO.js";
1
+ import { C as detectEffortCapability, D as AI_VIEW_NAME, E as AI_SETTINGS_KEY, O as OPEN_AI_SETTINGS_COMMAND, S as parseModelIds, T as AI_SETTINGS_EDITOR_ID, _ as readPromptAttachmentFromFile, b as defaultProvidersSettings, f as estimateSessionContextUsage, g as ATTACHMENT_FILE_ACCEPT, h as formatTokenCount, k as TOPIC, m as formatContextPercent, p as formatBucketDetail, r as cognitiveRuntime, t as registerSkillCommands, y as fetchOpenAICompatibleModels } from "./runtime-DVzLyx8h.js";
2
2
  import { DocksPart, File as File$1, FileContentType, SIDEBAR_AUXILIARY, confirmDialog, contributionRegistry, editorRegistry, filebrowserDialog, parseMarkdownHtml, registerAll, rootContext, toastError, toastInfo, workspaceService } from "@eclipse-docks/core";
3
3
  import { css, customElement, html, nothing, property, query, state, unsafeHTML } from "@eclipse-docks/core/externals/lit";
4
4
  import "@eclipse-docks/core/externals/webawesome";
@@ -64,6 +64,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
64
64
  this.toolDetail = null;
65
65
  this.busy = false;
66
66
  this.busyStatus = INITIAL_BUSY_STATUS;
67
+ this.queuedPrompt = null;
67
68
  this.pendingPermission = null;
68
69
  this.policyMode = "auto";
69
70
  this.optimizeFor = "balance";
@@ -408,6 +409,27 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
408
409
  min-width: 0;
409
410
  }
410
411
 
412
+ .queued-prompt {
413
+ display: flex;
414
+ align-items: center;
415
+ gap: var(--wa-space-2xs);
416
+ padding: var(--wa-space-2xs) var(--wa-space-s);
417
+ border-radius: var(--wa-border-radius-m);
418
+ border: var(--wa-border-width-s) solid var(--wa-color-border-normal);
419
+ background: color-mix(in srgb, var(--wa-color-brand-fill-quiet) 40%, transparent);
420
+ color: var(--wa-color-text-quiet);
421
+ font-size: var(--wa-font-size-s);
422
+ min-width: 0;
423
+ }
424
+
425
+ .queued-prompt-text {
426
+ flex: 1;
427
+ min-width: 0;
428
+ overflow: hidden;
429
+ text-overflow: ellipsis;
430
+ white-space: nowrap;
431
+ }
432
+
411
433
  .composer-row {
412
434
  display: flex;
413
435
  gap: var(--wa-space-s);
@@ -697,12 +719,10 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
697
719
  startBusyStatus() {
698
720
  this.stopBusyStatus();
699
721
  this.busyStatus = INITIAL_BUSY_STATUS;
700
- this.setComposerText(this.busyStatus);
701
722
  window.addEventListener("keydown", this.cancelKeyHandler);
702
723
  const schedule = () => {
703
724
  this.busyStatusTimer = setTimeout(() => {
704
725
  this.busyStatus = nextBusyStatus(this.busyStatus);
705
- this.setComposerText(this.busyStatus);
706
726
  schedule();
707
727
  }, busyStatusRotateMs());
708
728
  };
@@ -975,10 +995,6 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
975
995
  }
976
996
  /** Attach clipboard files/images (e.g. Ctrl+V screenshot) when focused in the prompt. */
977
997
  async onComposerPaste(e) {
978
- if (this.busy) {
979
- e.preventDefault();
980
- return;
981
- }
982
998
  const files = filesFromClipboard(e.clipboardData);
983
999
  if (!files.length) return;
984
1000
  e.preventDefault();
@@ -989,13 +1005,30 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
989
1005
  this.promptController?.abort();
990
1006
  if (this.pendingPermission) this.resolvePermission("deny");
991
1007
  }
1008
+ clearQueuedPrompt() {
1009
+ this.queuedPrompt = null;
1010
+ }
1011
+ async queueFollowUp(text, attachmentIds) {
1012
+ this.queuedPrompt = {
1013
+ text,
1014
+ attachmentIds
1015
+ };
1016
+ this.pendingAttachmentIds = [];
1017
+ if (this.fileInput) this.fileInput.value = "";
1018
+ await this.setComposerText("");
1019
+ }
992
1020
  async send() {
993
1021
  const text = this.draft.trim();
994
1022
  const attachmentIds = [...this.pendingAttachmentIds];
995
- if (!text && !attachmentIds.length || this.busy) return;
1023
+ if (!text && !attachmentIds.length) return;
1024
+ if (this.busy) {
1025
+ await this.queueFollowUp(text, attachmentIds);
1026
+ return;
1027
+ }
996
1028
  this.applyPolicy();
997
1029
  this.pendingAttachmentIds = [];
998
1030
  if (this.fileInput) this.fileInput.value = "";
1031
+ await this.setComposerText("");
999
1032
  const controller = new AbortController();
1000
1033
  this.promptController = controller;
1001
1034
  this.busy = true;
@@ -1013,9 +1046,18 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1013
1046
  this.stopBusyStatus();
1014
1047
  this.busy = false;
1015
1048
  this.streamingParts = [];
1016
- await this.clearComposer();
1017
1049
  this.syncSessions();
1018
1050
  this.scheduleScrollToBottom();
1051
+ const next = this.queuedPrompt;
1052
+ this.queuedPrompt = null;
1053
+ if (next && (next.text.trim() || next.attachmentIds.length)) {
1054
+ this.draft = next.text;
1055
+ this.pendingAttachmentIds = next.attachmentIds;
1056
+ await this.updateComplete;
1057
+ if (this.textarea) this.textarea.value = next.text;
1058
+ await this.send();
1059
+ return;
1060
+ }
1019
1061
  this.textarea?.focus();
1020
1062
  }
1021
1063
  }
@@ -1029,7 +1071,6 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1029
1071
  size="s"
1030
1072
  appearance="plain"
1031
1073
  title=${count ? `${count} attachment${count === 1 ? "" : "s"}` : "Attachments"}
1032
- ?disabled=${this.busy}
1033
1074
  >
1034
1075
  <wa-icon name="paperclip" label="Attachments"></wa-icon>
1035
1076
  ${count > 0 ? html`<wa-badge pill>${count}</wa-badge>` : nothing}
@@ -1064,7 +1105,6 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1064
1105
  size="s"
1065
1106
  appearance="plain"
1066
1107
  title=${`Save ${file.name} to workspace folder`}
1067
- ?disabled=${this.busy}
1068
1108
  @click=${() => void this.saveAttachmentToWorkspace(file.id)}
1069
1109
  >
1070
1110
  <wa-icon name="floppy-disk" label=${`Save ${file.name}`}></wa-icon>
@@ -1073,7 +1113,6 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1073
1113
  size="s"
1074
1114
  appearance="plain"
1075
1115
  title="Remove from session"
1076
- ?disabled=${this.busy}
1077
1116
  @click=${() => this.removeSessionAttachment(file.id)}
1078
1117
  >
1079
1118
  <wa-icon name="xmark" label="Remove"></wa-icon>
@@ -1085,7 +1124,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1085
1124
  <wa-button
1086
1125
  size="s"
1087
1126
  appearance="outlined"
1088
- ?disabled=${this.busy || count >= 8}
1127
+ ?disabled=${count >= 8}
1089
1128
  @click=${() => this.openFilePicker()}
1090
1129
  >
1091
1130
  <wa-icon slot="start" name="plus"></wa-icon>
@@ -1304,27 +1343,36 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1304
1343
  @change=${(e) => void this.onFileInputChange(e)}
1305
1344
  />
1306
1345
  <div class="composer">
1346
+ ${this.queuedPrompt ? html`
1347
+ <div class="queued-prompt" title="Sends automatically when the current turn finishes">
1348
+ <wa-icon name="clock"></wa-icon>
1349
+ <span class="queued-prompt-text">
1350
+ Queued: ${this.queuedPrompt.text.trim() || `(${this.queuedPrompt.attachmentIds.length} attachment${this.queuedPrompt.attachmentIds.length === 1 ? "" : "s"})`}
1351
+ </span>
1352
+ <wa-button
1353
+ size="s"
1354
+ appearance="plain"
1355
+ title="Remove queued follow-up"
1356
+ @click=${() => this.clearQueuedPrompt()}
1357
+ >
1358
+ <wa-icon name="xmark" label="Remove queue"></wa-icon>
1359
+ </wa-button>
1360
+ </div>
1361
+ ` : nothing}
1307
1362
  <div class="composer-row">
1308
1363
  <wa-textarea
1309
- placeholder=${this.busy ? this.busyStatus : "Enter your message here…"}
1364
+ placeholder=${this.busy ? "Add a follow-up…" : "Enter your message here…"}
1310
1365
  size="s"
1311
1366
  resize="auto"
1312
1367
  rows="1"
1313
- .value=${this.busy ? this.busyStatus : this.draft}
1314
- ?disabled=${this.busy}
1315
- ?readonly=${this.busy}
1368
+ .value=${this.draft}
1316
1369
  @input=${(e) => {
1317
- if (this.busy) return;
1318
1370
  this.draft = e.target.value;
1319
1371
  }}
1320
1372
  @keydown=${(e) => {
1321
- if (this.busy) {
1322
- if (e.key === "Escape") {
1323
- e.preventDefault();
1324
- this.cancelTurn();
1325
- return;
1326
- }
1373
+ if (e.key === "Escape" && this.busy) {
1327
1374
  e.preventDefault();
1375
+ this.cancelTurn();
1328
1376
  return;
1329
1377
  }
1330
1378
  if (e.key === "Enter" && !e.shiftKey) {
@@ -1357,7 +1405,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1357
1405
  `;
1358
1406
  }
1359
1407
  renderTranscript(session) {
1360
- const showStreaming = this.streamingParts.length > 0;
1408
+ const showStreaming = this.busy || this.streamingParts.length > 0;
1361
1409
  const showPermission = this.pendingPermission && this.pendingPermission.sessionId === session.id;
1362
1410
  return html`
1363
1411
  ${session.history.map((m) => this.renderMessage(m))}
@@ -1717,6 +1765,7 @@ _decorate([state()], DocksCognitiveView.prototype, "previewAttachmentId", void 0
1717
1765
  _decorate([state()], DocksCognitiveView.prototype, "toolDetail", void 0);
1718
1766
  _decorate([state()], DocksCognitiveView.prototype, "busy", void 0);
1719
1767
  _decorate([state()], DocksCognitiveView.prototype, "busyStatus", void 0);
1768
+ _decorate([state()], DocksCognitiveView.prototype, "queuedPrompt", void 0);
1720
1769
  _decorate([state()], DocksCognitiveView.prototype, "pendingPermission", void 0);
1721
1770
  _decorate([state()], DocksCognitiveView.prototype, "policyMode", void 0);
1722
1771
  _decorate([state()], DocksCognitiveView.prototype, "optimizeFor", void 0);
@@ -2548,4 +2597,4 @@ registerAll({
2548
2597
  });
2549
2598
  //#endregion
2550
2599
 
2551
- //# sourceMappingURL=cognitive-extension-BKGxwLYj.js.map
2600
+ //# sourceMappingURL=cognitive-extension-CvP05Bw_.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cognitive-extension-CvP05Bw_.js","names":["WorkspaceFile","APPROVAL_OPTIONS"],"sources":["../src/view/busy-status.ts","../src/view/cognitive-view.ts","../src/view/cognitive-settings-editor.ts","../src/cognitive-extension.ts"],"sourcesContent":["/** Shown immediately when waiting on a model turn. */\nexport const INITIAL_BUSY_STATUS = 'Thinking…';\n\n/**\n * Rotating wait copy (Cursor / Copilot style). Picked at random after the initial message.\n * Keep these light and short — they appear in the composer while busy.\n */\nexport const BUSY_STATUS_MESSAGES: readonly string[] = [\n 'Bribing the hamster…',\n 'Consulting the rubber duck…',\n 'Untangling the spaghetti…',\n 'Herding tokens…',\n 'Warming up the crystals…',\n 'Counting electric sheep…',\n 'Negotiating with the compiler…',\n 'Teaching frogs to code…',\n 'Aligning the bits…',\n 'Feeding the GPU snacks…',\n 'Looking under the couch…',\n 'Summoning a specialist…',\n 'Checking the manual twice…',\n 'Reticulating splines…',\n 'Sharpening pencils…',\n 'Pedaling harder…',\n 'Buffering brilliance…',\n 'Reversing the polarity…',\n 'Convincing the bits to cooperate…',\n 'Dusting off the playbook…',\n 'Whispering to the model…',\n 'Calibrating optimism…',\n 'Unfolding the roadmap…',\n 'Polishing ones and zeros…',\n 'Asking politely…',\n];\n\nconst ROTATE_MS_MIN = 3_000;\nconst ROTATE_MS_MAX = 12_000;\n\n/** Random delay until the next busy-status line (3–12s). */\nexport function busyStatusRotateMs(): number {\n return ROTATE_MS_MIN + Math.floor(Math.random() * (ROTATE_MS_MAX - ROTATE_MS_MIN + 1));\n}\n\n/** Next status, avoiding an immediate repeat of `current`. */\nexport function nextBusyStatus(current: string): string {\n const pool = BUSY_STATUS_MESSAGES.filter((m) => m !== current);\n if (!pool.length) return INITIAL_BUSY_STATUS;\n return pool[Math.floor(Math.random() * pool.length)]!;\n}\n","import '@eclipse-docks/core/externals/webawesome';\nimport {\n html,\n css,\n nothing,\n customElement,\n query,\n state,\n unsafeHTML,\n type TemplateResult,\n} from '@eclipse-docks/core/externals/lit';\nimport {\n DocksPart,\n File as WorkspaceFile,\n FileContentType,\n filebrowserDialog,\n parseMarkdownHtml,\n toastError,\n toastInfo,\n workspaceService,\n} from '@eclipse-docks/core';\nimport {\n ATTACHMENT_FILE_ACCEPT,\n MAX_ATTACHMENTS,\n OPEN_AI_SETTINGS_COMMAND,\n TOPIC,\n cognitiveRuntime,\n detectEffortCapability,\n estimateSessionContextUsage,\n formatBucketDetail,\n formatContextPercent,\n formatTokenCount,\n readPromptAttachmentFromFile,\n} from '../runtime';\nimport type {\n ChatMessage,\n CognitiveSession,\n ContextUsage,\n EffortLevel,\n MessagePart,\n ModelPolicy,\n PermissionAction,\n PromptAttachment,\n SessionAttachment,\n ToolApprovalMode,\n} from '../runtime';\nimport {\n INITIAL_BUSY_STATUS,\n busyStatusRotateMs,\n nextBusyStatus,\n} from './busy-status';\n\ninterface PermissionRequest {\n requestId: string;\n toolName: string;\n args: Record<string, unknown>;\n sessionId: string;\n}\n\n@customElement('docks-cognitive-view')\nexport class DocksCognitiveView extends DocksPart {\n protected scrollMode: 'scroller' | 'native' | 'none' = 'none';\n\n static styles = css`\n :host {\n height: 100%;\n min-height: 0;\n background: var(--wa-color-surface-default);\n color: var(--wa-color-text-normal);\n font-family: var(--wa-font-family-body);\n }\n\n .part-content,\n .part-content-inner {\n height: 100%;\n min-height: 0;\n }\n\n .cognitive-shell {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n /* Establish a definite containing block for wa-scroller's height: 100%. */\n position: relative;\n }\n\n wa-dropdown.history-menu::part(menu) {\n min-width: 18rem;\n max-width: min(24rem, 92vw);\n max-height: min(28rem, 70vh);\n overflow-y: auto;\n padding-top: 0;\n }\n\n .history-search {\n position: sticky;\n top: 0;\n z-index: 1;\n display: block;\n padding: var(--wa-space-s);\n background: var(--wa-color-surface-raised);\n border-bottom: var(--wa-border-width-s) solid var(--wa-color-border-normal);\n }\n\n .history-search wa-input {\n width: 100%;\n }\n\n .history-item-title {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .history-item-meta {\n color: var(--wa-color-text-quiet);\n font-size: var(--wa-font-size-xs);\n flex-shrink: 0;\n }\n\n .history-empty {\n padding: var(--wa-space-m);\n color: var(--wa-color-text-quiet);\n font-size: var(--wa-font-size-s);\n text-align: center;\n }\n\n wa-scroller.transcript {\n /* flex-basis 0 so the host gets a definite height; wa-scroller vertical uses height:100%. */\n flex: 1 1 0;\n min-height: 0;\n height: 100%;\n overflow: hidden;\n }\n\n .transcript-inner {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-m);\n padding: var(--wa-space-m);\n min-height: 100%;\n box-sizing: border-box;\n }\n\n /* Pushes short threads to the bottom without breaking overflow scroll. */\n .transcript-spacer {\n flex: 1 0 0;\n min-height: 0;\n }\n\n .msg {\n position: relative;\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-2xs);\n width: 90%;\n min-width: 90%;\n max-width: 90%;\n align-self: flex-start;\n align-items: stretch;\n }\n\n .msg.user {\n align-self: flex-end;\n }\n\n .msg .bubble,\n .msg wa-details.msg-details {\n width: 100%;\n box-sizing: border-box;\n }\n\n .msg-meta {\n position: absolute;\n right: var(--wa-space-2xs);\n bottom: var(--wa-space-2xs);\n z-index: 1;\n display: flex;\n gap: var(--wa-space-2xs);\n align-items: center;\n flex-wrap: wrap;\n justify-content: flex-end;\n max-width: calc(100% - var(--wa-space-s));\n padding: var(--wa-space-3xs) var(--wa-space-2xs);\n border-radius: var(--wa-border-radius-m);\n background: color-mix(in srgb, var(--wa-color-surface-default) 88%, transparent);\n font-size: var(--wa-font-size-xs);\n color: var(--wa-color-text-quiet);\n opacity: 0;\n pointer-events: none;\n transition: opacity var(--wa-transition-fast, 120ms) ease;\n }\n\n .msg:hover .msg-meta,\n .msg:focus-within .msg-meta {\n opacity: 1;\n pointer-events: auto;\n }\n\n .bubble {\n padding: var(--wa-space-s) var(--wa-space-m);\n border-radius: var(--wa-border-radius-l);\n background: var(--wa-color-surface-raised);\n border: var(--wa-border-width-s) solid var(--wa-color-border-normal);\n white-space: pre-wrap;\n line-height: var(--wa-line-height-normal);\n max-width: 100%;\n overflow-wrap: anywhere;\n }\n\n .bubble.markdown {\n white-space: normal;\n }\n\n .bubble.markdown > :first-child {\n margin-block-start: 0;\n }\n\n .bubble.markdown > :last-child {\n margin-block-end: 0;\n }\n\n .bubble.markdown pre {\n overflow-x: auto;\n padding: var(--wa-space-s);\n border-radius: var(--wa-border-radius-m);\n background: color-mix(in srgb, var(--wa-color-neutral-fill-quiet) 55%, transparent);\n }\n\n .bubble.markdown code {\n font-family: var(--wa-font-family-code, ui-monospace, monospace);\n font-size: 0.92em;\n }\n\n .bubble.markdown pre code {\n font-size: inherit;\n }\n\n .bubble.markdown a {\n color: var(--wa-color-brand-on-normal);\n }\n\n .msg.user .bubble {\n background: color-mix(in srgb, var(--wa-color-brand-fill-normal) 22%, transparent);\n border-color: color-mix(in srgb, var(--wa-color-brand-fill-normal) 40%, transparent);\n }\n\n .streaming-meta {\n display: flex;\n gap: var(--wa-space-2xs);\n align-items: center;\n color: var(--wa-color-text-quiet);\n font-size: var(--wa-font-size-s);\n }\n\n .composer-shell {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-s);\n padding: var(--wa-space-s) var(--wa-space-m) var(--wa-space-m);\n border-top: var(--wa-border-width-s) solid var(--wa-color-border-normal);\n flex-shrink: 0;\n }\n\n wa-dropdown.settings-menu::part(menu) {\n min-width: 16rem;\n max-width: min(28rem, 92vw);\n }\n\n wa-dropdown.context-menu::part(menu) {\n min-width: 17rem;\n max-width: min(22rem, 92vw);\n padding: var(--wa-space-s);\n }\n\n .context-ring {\n --size: 1.35rem;\n --track-width: 2.5px;\n --indicator-width: 2.5px;\n font-size: 0;\n }\n\n .context-panel {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-s);\n }\n\n .context-header {\n display: flex;\n justify-content: space-between;\n align-items: baseline;\n gap: var(--wa-space-s);\n }\n\n .context-header strong {\n font-size: var(--wa-font-size-s);\n }\n\n .context-header span {\n color: var(--wa-color-text-quiet);\n font-size: var(--wa-font-size-xs);\n }\n\n .context-bars {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-2xs);\n }\n\n .context-row {\n display: grid;\n grid-template-columns: 1fr auto;\n gap: var(--wa-space-2xs);\n font-size: var(--wa-font-size-xs);\n }\n\n .context-row-label {\n color: var(--wa-color-text-quiet);\n }\n\n .context-meter {\n grid-column: 1 / -1;\n height: 0.35rem;\n border-radius: var(--wa-border-radius-pill);\n background: var(--wa-color-neutral-fill-quiet);\n overflow: hidden;\n }\n\n .context-meter > span {\n display: block;\n height: 100%;\n border-radius: inherit;\n background: var(--bucket-color, var(--wa-color-brand-fill-normal));\n }\n\n .context-io {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: var(--wa-space-2xs);\n padding-top: var(--wa-space-s);\n border-top: var(--wa-border-width-s) solid var(--wa-color-border-normal);\n font-size: var(--wa-font-size-xs);\n }\n\n .context-io-heading {\n grid-column: 1 / -1;\n font-weight: var(--wa-font-weight-semibold, 600);\n }\n\n .context-io-item {\n display: flex;\n flex-direction: column;\n gap: 0.1rem;\n }\n\n .context-io-item span {\n color: var(--wa-color-text-quiet);\n }\n\n .context-io-item strong {\n font-variant-numeric: tabular-nums;\n }\n\n .context-footer {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-2xs);\n }\n\n .context-remaining {\n color: var(--wa-color-text-quiet);\n font-size: var(--wa-font-size-xs);\n }\n\n .composer {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-2xs);\n flex: 1;\n min-width: 0;\n }\n\n .queued-prompt {\n display: flex;\n align-items: center;\n gap: var(--wa-space-2xs);\n padding: var(--wa-space-2xs) var(--wa-space-s);\n border-radius: var(--wa-border-radius-m);\n border: var(--wa-border-width-s) solid var(--wa-color-border-normal);\n background: color-mix(in srgb, var(--wa-color-brand-fill-quiet) 40%, transparent);\n color: var(--wa-color-text-quiet);\n font-size: var(--wa-font-size-s);\n min-width: 0;\n }\n\n .queued-prompt-text {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .composer-row {\n display: flex;\n gap: var(--wa-space-s);\n align-items: flex-end;\n }\n\n .composer wa-textarea {\n flex: 1;\n min-width: 0;\n }\n\n .composer-actions {\n display: flex;\n align-items: center;\n gap: var(--wa-space-2xs);\n flex-shrink: 0;\n }\n\n .composer-shell.drag-over {\n outline: 2px dashed var(--wa-color-brand-border-normal);\n outline-offset: -2px;\n background: color-mix(in srgb, var(--wa-color-brand-fill-quiet) 35%, transparent);\n }\n\n wa-dropdown.attach-menu::part(menu) {\n min-width: 18rem;\n max-width: min(24rem, 92vw);\n padding: var(--wa-space-2xs);\n }\n\n .attach-panel {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-2xs);\n max-height: min(22rem, 50vh);\n }\n\n .attach-list {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-2xs);\n overflow: auto;\n min-height: 0;\n }\n\n .attach-row {\n display: flex;\n align-items: center;\n gap: var(--wa-space-2xs);\n min-width: 0;\n }\n\n .attach-preview-btn {\n display: flex;\n align-items: center;\n gap: var(--wa-space-s);\n flex: 1;\n min-width: 0;\n margin: 0;\n padding: var(--wa-space-2xs);\n border: none;\n border-radius: var(--wa-border-radius-s);\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: start;\n cursor: pointer;\n }\n\n .attach-preview-btn:hover {\n background: var(--wa-color-neutral-fill-quiet);\n }\n\n .attach-thumb,\n .msg-file-thumb {\n width: 2.5rem;\n height: 2.5rem;\n object-fit: cover;\n border-radius: var(--wa-border-radius-s);\n border: var(--wa-border-width-s) solid var(--wa-color-border-normal);\n flex-shrink: 0;\n }\n\n .attach-file-icon {\n display: grid;\n place-items: center;\n width: 2.5rem;\n height: 2.5rem;\n border-radius: var(--wa-border-radius-s);\n border: var(--wa-border-width-s) solid var(--wa-color-border-normal);\n color: var(--wa-color-text-quiet);\n flex-shrink: 0;\n }\n\n .attach-name {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--wa-font-size-s);\n }\n\n .attach-empty {\n color: var(--wa-color-text-quiet);\n font-size: var(--wa-font-size-xs);\n padding: var(--wa-space-s);\n }\n\n .msg-file-thumb {\n width: 4.5rem;\n height: 4.5rem;\n }\n\n .attach-dialog-body {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-s);\n max-height: min(70vh, 40rem);\n overflow: auto;\n }\n\n .attach-dialog-image {\n max-width: 100%;\n height: auto;\n border-radius: var(--wa-border-radius-m);\n }\n\n .attach-dialog-text {\n margin: 0;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: var(--wa-font-family-code, ui-monospace, monospace);\n font-size: var(--wa-font-size-s);\n }\n\n .msg-files {\n display: flex;\n flex-wrap: wrap;\n gap: var(--wa-space-2xs);\n margin-bottom: var(--wa-space-2xs);\n }\n\n .approval-actions {\n display: flex;\n gap: var(--wa-space-s);\n margin-top: var(--wa-space-s);\n flex-wrap: wrap;\n }\n\n pre.args {\n margin: var(--wa-space-s) 0 0;\n font-family: var(--wa-font-family-code, var(--wa-font-mono));\n font-size: var(--wa-font-size-xs);\n white-space: pre-wrap;\n overflow-x: auto;\n }\n\n wa-details {\n font-size: var(--wa-font-size-s);\n }\n\n wa-details.msg-details {\n width: 100%;\n font-size: var(--wa-font-size-s);\n }\n\n wa-details.msg-details::part(base),\n wa-details.msg-details::part(details) {\n border: none;\n background: transparent;\n }\n\n wa-details.msg-details::part(header) {\n align-items: flex-start;\n gap: var(--wa-space-2xs);\n padding: 0;\n }\n\n wa-details.msg-details::part(summary) {\n flex: 1;\n min-width: 0;\n }\n\n wa-details.msg-details::part(content) {\n padding: var(--wa-space-s) 0 0;\n }\n\n .msg-summary {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-2xs);\n width: 100%;\n }\n\n .msg-tech {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-s);\n margin-inline-start: var(--wa-space-l);\n padding-inline-start: var(--wa-space-m);\n border-inline-start: var(--wa-border-width-s) solid var(--wa-color-border-normal);\n }\n\n .tool-heading {\n font-size: var(--wa-font-size-xs);\n color: var(--wa-color-text-quiet);\n margin-bottom: var(--wa-space-2xs);\n }\n\n .tool-row {\n display: flex;\n align-items: center;\n gap: var(--wa-space-2xs);\n flex-wrap: wrap;\n }\n\n .tool-row .tool-heading {\n margin-bottom: 0;\n flex: 1;\n min-width: 0;\n }\n\n .tool-detail-body {\n max-height: min(70vh, 36rem);\n overflow: auto;\n }\n\n .tool-detail-body pre {\n margin: 0;\n font-family: var(--wa-font-family-code, var(--wa-font-mono));\n font-size: var(--wa-font-size-xs);\n white-space: pre-wrap;\n word-break: break-word;\n }\n `;\n\n @query('wa-textarea') private textarea?: HTMLElement & { value: string; shadowRoot: ShadowRoot | null };\n @query('#attach-file-input') private fileInput?: HTMLInputElement;\n private composerPasteBound = false;\n\n @state() private sessions: CognitiveSession[] = [];\n @state() private focusedId: string | null = null;\n @state() private draft = '';\n /** Session attachment ids to publish with the next user turn. */\n @state() private pendingAttachmentIds: string[] = [];\n @state() private dragOver = false;\n @state() private previewAttachmentId: string | null = null;\n @state() private toolDetail: Extract<MessagePart, { type: 'tool' }> | null = null;\n @state() private busy = false;\n @state() private busyStatus = INITIAL_BUSY_STATUS;\n /** Follow-up composed while a turn is running; sent automatically when the turn ends. */\n @state() private queuedPrompt: { text: string; attachmentIds: string[] } | null = null;\n @state() private pendingPermission: PermissionRequest | null = null;\n @state() private policyMode: 'auto' | 'manual' = 'auto';\n @state() private optimizeFor: 'cost' | 'balance' | 'intelligence' = 'balance';\n @state() private manualModel = '';\n @state() private manualEffort: EffortLevel | 'auto' = 'auto';\n @state() private approvalMode: ToolApprovalMode = 'auto_safe';\n @state() private modelIds: string[] = [];\n @state() private streamingParts: MessagePart[] = [];\n @state() private historyOpen = false;\n @state() private historyQuery = '';\n private unsubs: Array<() => void> = [];\n private scrollDebounceTimer?: ReturnType<typeof setTimeout>;\n private busyStatusTimer?: ReturnType<typeof setTimeout>;\n private promptController: AbortController | null = null;\n private nativePasteHandler = (e: Event) => void this.onComposerPaste(e as ClipboardEvent);\n private cancelKeyHandler = (e: KeyboardEvent) => {\n if (!this.busy || e.key !== 'Escape') return;\n e.preventDefault();\n this.cancelTurn();\n };\n\n protected updated(): void {\n this.bindComposerPaste();\n }\n\n private bindComposerPaste(): void {\n if (this.composerPasteBound) return;\n const native = this.textarea?.shadowRoot?.querySelector('textarea');\n if (!native) return;\n native.addEventListener('paste', this.nativePasteHandler);\n this.composerPasteBound = true;\n }\n\n protected doBeforeUI(): void {\n cognitiveRuntime.start();\n this.syncSessions();\n this.syncModels();\n this.approvalMode = cognitiveRuntime.getApprovalMode();\n void cognitiveRuntime.whenReady().then(() => {\n this.syncSessions();\n this.restoreRoutingFromRuntime();\n this.scheduleScrollToBottom();\n });\n this.unsubs.push(\n cognitiveRuntime.events.subscribe(TOPIC.sessionChanged, () => {\n this.syncSessions();\n this.scheduleScrollToBottom();\n }),\n cognitiveRuntime.events.subscribe(TOPIC.providersChanged, () => this.onProvidersChanged()),\n cognitiveRuntime.events.subscribe(TOPIC.approvalModeChanged, (mode) => {\n this.approvalMode = mode as ToolApprovalMode;\n }),\n cognitiveRuntime.events.subscribe(TOPIC.permissionAsked, (payload) => {\n this.pendingPermission = payload as PermissionRequest;\n this.scheduleScrollToBottom();\n }),\n cognitiveRuntime.events.subscribe(TOPIC.messagePart, (payload) => {\n const { sessionId, part } = payload as { sessionId: string; part: MessagePart };\n if (sessionId !== this.focusedId) return;\n this.streamingParts = mergePart(this.streamingParts, part);\n this.scheduleScrollToBottom();\n }),\n cognitiveRuntime.events.subscribe(TOPIC.messageDone, () => {\n this.streamingParts = [];\n this.syncSessions();\n this.scheduleScrollToBottom();\n }),\n );\n }\n\n protected doClose(): void {\n if (this.scrollDebounceTimer) clearTimeout(this.scrollDebounceTimer);\n this.scrollDebounceTimer = undefined;\n this.cancelTurn();\n this.stopBusyStatus();\n const native = this.textarea?.shadowRoot?.querySelector('textarea');\n native?.removeEventListener('paste', this.nativePasteHandler);\n this.composerPasteBound = false;\n for (const u of this.unsubs) u();\n this.unsubs = [];\n }\n\n private startBusyStatus(): void {\n this.stopBusyStatus();\n this.busyStatus = INITIAL_BUSY_STATUS;\n window.addEventListener('keydown', this.cancelKeyHandler);\n const schedule = () => {\n this.busyStatusTimer = setTimeout(() => {\n this.busyStatus = nextBusyStatus(this.busyStatus);\n schedule();\n }, busyStatusRotateMs());\n };\n schedule();\n }\n\n private stopBusyStatus(): void {\n if (this.busyStatusTimer) clearTimeout(this.busyStatusTimer);\n this.busyStatusTimer = undefined;\n this.busyStatus = INITIAL_BUSY_STATUS;\n window.removeEventListener('keydown', this.cancelKeyHandler);\n }\n\n private syncSessions(): void {\n const byRecency = cognitiveRuntime.sessions.list();\n this.sessions = [...byRecency].sort((a, b) => a.createdAt - b.createdAt);\n const focused = cognitiveRuntime.sessions.focused();\n const activeId = focused?.id ?? byRecency[0]?.id ?? null;\n if (activeId && focused?.id !== activeId) {\n cognitiveRuntime.sessions.focus(activeId);\n }\n this.focusedId = activeId;\n }\n\n private scheduleScrollToBottom(): void {\n if (this.scrollDebounceTimer) clearTimeout(this.scrollDebounceTimer);\n this.scrollDebounceTimer = setTimeout(() => {\n this.scrollDebounceTimer = undefined;\n void this.scrollToBottom();\n }, 50);\n }\n\n private async scrollToBottom(): Promise<void> {\n await this.updateComplete;\n await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()));\n const scroller = this.renderRoot.querySelector('wa-scroller.transcript');\n if (!scroller?.shadowRoot) return;\n\n const container = scroller.shadowRoot.querySelector('#content');\n if (!(container instanceof HTMLElement)) return;\n container.scrollTop = container.scrollHeight;\n }\n\n private focusedSession(): CognitiveSession | undefined {\n return this.sessions.find((s) => s.id === this.focusedId) ?? this.sessions[0];\n }\n\n private deleteSession(sessionId: string): void {\n if (this.sessions.length <= 1) {\n cognitiveRuntime.sessions.createSession({ title: 'Chat' });\n cognitiveRuntime.removeSession(sessionId);\n } else {\n cognitiveRuntime.removeSession(sessionId);\n }\n this.streamingParts = [];\n this.syncSessions();\n }\n\n private openSession(sessionId: string): void {\n if (!cognitiveRuntime.sessions.focus(sessionId)) return;\n this.streamingParts = [];\n this.syncSessions();\n this.historyOpen = false;\n this.historyQuery = '';\n cognitiveRuntime.commitSessions();\n this.scheduleScrollToBottom();\n }\n\n private newSession(): void {\n cognitiveRuntime.sessions.createSession({ title: 'Chat' });\n this.streamingParts = [];\n this.historyOpen = false;\n this.historyQuery = '';\n this.syncSessions();\n cognitiveRuntime.commitSessions();\n }\n\n private historySessions(): CognitiveSession[] {\n const q = this.historyQuery.trim().toLowerCase();\n const sorted = [...this.sessions].sort((a, b) => b.updatedAt - a.updatedAt);\n if (!q) return sorted;\n return sorted.filter((s) => {\n if (s.title.toLowerCase().includes(q)) return true;\n return s.history.some((m) =>\n m.parts.some((p) => {\n if (p.type === 'text') return p.text.toLowerCase().includes(q);\n if (p.type === 'file') {\n return (\n p.name.toLowerCase().includes(q) ||\n p.id.toLowerCase().includes(q) ||\n (p.path?.toLowerCase().includes(q) ?? false)\n );\n }\n return false;\n }),\n );\n });\n }\n\n private syncModels(): void {\n this.modelIds = cognitiveRuntime.listConfiguredModels();\n if (!this.manualModel || !this.modelIds.includes(this.manualModel)) {\n this.manualModel = this.modelIds[0] ?? cognitiveRuntime.defaultModelId();\n }\n }\n\n /** Mirror persisted runtime policy into the gear menu after hydrate. */\n private restoreRoutingFromRuntime(): void {\n this.syncModels();\n const policy = cognitiveRuntime.getModelPolicy();\n if (policy.mode === 'auto') {\n this.policyMode = 'auto';\n this.optimizeFor = policy.optimizeFor;\n } else {\n this.policyMode = 'manual';\n this.manualModel = policy.model;\n this.manualEffort = policy.effort ?? 'auto';\n if (!this.manualModel || !this.modelIds.includes(this.manualModel)) {\n this.manualModel = this.modelIds[0] ?? cognitiveRuntime.defaultModelId();\n this.applyPolicy();\n }\n }\n this.approvalMode = cognitiveRuntime.getApprovalMode();\n }\n\n private onProvidersChanged(): void {\n this.syncModels();\n if (this.policyMode !== 'manual') return;\n if (this.manualModel && this.modelIds.includes(this.manualModel)) return;\n this.manualModel = this.modelIds[0] ?? cognitiveRuntime.defaultModelId();\n this.applyPolicy();\n }\n\n private effortChoices(): Array<EffortLevel | 'auto'> {\n const cap = detectEffortCapability(this.manualModel || cognitiveRuntime.defaultModelId());\n if (!cap.supported) return ['auto', 'none'];\n return ['auto', ...cap.levels];\n }\n\n private routerValue(): string {\n return this.policyMode === 'auto' ? `auto:${this.optimizeFor}` : `model:${this.manualModel}`;\n }\n\n private routerLabel(): string {\n if (this.policyMode === 'auto') return `Auto · ${capitalize(this.optimizeFor)}`;\n if (!this.modelIds.length) return 'No models';\n return shortModelLabel(this.manualModel || this.modelIds[0]!);\n }\n\n private activeModelRef(): string {\n const session = this.focusedSession();\n const routed = [...(session?.history ?? [])]\n .reverse()\n .find((m) => m.role === 'assistant' && m.routedModel)?.routedModel;\n if (routed) return routed;\n if (this.policyMode === 'manual') {\n return this.manualModel || this.modelIds[0] || cognitiveRuntime.defaultModelId();\n }\n return this.modelIds[0] || cognitiveRuntime.defaultModelId();\n }\n\n private contextUsage(): ContextUsage {\n return estimateSessionContextUsage(this.focusedSession(), this.activeModelRef());\n }\n\n private async compactFocused(): Promise<void> {\n if (!this.focusedId) return;\n await cognitiveRuntime.compactSession(this.focusedId);\n this.syncSessions();\n }\n\n private onRouterSelect(value: string): void {\n if (value.startsWith('auto:')) {\n const optimize = value.slice(5);\n if (optimize === 'cost' || optimize === 'balance' || optimize === 'intelligence') {\n this.policyMode = 'auto';\n this.optimizeFor = optimize;\n this.applyPolicy();\n }\n return;\n }\n if (value.startsWith('model:')) {\n const model = value.slice(6);\n if (!model) return;\n this.policyMode = 'manual';\n this.manualModel = model;\n this.applyPolicy();\n }\n }\n\n private applyPolicy(): void {\n const policy: ModelPolicy =\n this.policyMode === 'manual'\n ? {\n mode: 'manual',\n model: this.manualModel || cognitiveRuntime.defaultModelId(),\n effort: this.manualEffort,\n }\n : { mode: 'auto', optimizeFor: this.optimizeFor };\n cognitiveRuntime.setModelPolicy(policy);\n }\n\n private async setComposerText(value: string): Promise<void> {\n this.draft = value;\n await this.updateComplete;\n if (this.textarea) this.textarea.value = value;\n }\n\n private async clearComposer(): Promise<void> {\n this.pendingAttachmentIds = [];\n if (this.fileInput) this.fileInput.value = '';\n await this.setComposerText('');\n }\n\n private sessionAttachments(): SessionAttachment[] {\n return this.focusedSession()?.attachments ?? [];\n }\n\n private previewAttachment(): SessionAttachment | undefined {\n if (!this.previewAttachmentId) return undefined;\n return this.sessionAttachments().find((a) => a.id === this.previewAttachmentId);\n }\n\n private openAttachmentPreview(attachmentId: string): void {\n this.previewAttachmentId = attachmentId;\n }\n\n private closeAttachmentPreview(): void {\n this.previewAttachmentId = null;\n }\n\n private removeSessionAttachment(attachmentId: string): void {\n const sessionId = this.focusedId ?? cognitiveRuntime.ensureSessionId();\n cognitiveRuntime.removeAttachment(sessionId, attachmentId);\n this.pendingAttachmentIds = this.pendingAttachmentIds.filter((id) => id !== attachmentId);\n if (this.previewAttachmentId === attachmentId) this.previewAttachmentId = null;\n this.syncSessions();\n }\n\n private async saveAttachmentToWorkspace(attachmentId: string): Promise<void> {\n const attachment = this.sessionAttachments().find((a) => a.id === attachmentId);\n if (!attachment) return;\n\n const preferredName = attachmentSaveFileName(attachment);\n const parent = await filebrowserDialog('directory');\n if (!parent) return;\n\n try {\n const workspace = await workspaceService.getWorkspace();\n if (!workspace) {\n toastError('No workspace connected');\n return;\n }\n const parentPath = parent.replace(/\\/$/, '');\n const fileName = await uniqueWorkspaceFileName(workspace, parentPath, preferredName);\n const path = `${parentPath}/${fileName}`;\n const resource = await workspace.getResource(path, { create: true });\n if (!(resource instanceof WorkspaceFile)) {\n toastError('Could not create file in the selected folder');\n return;\n }\n\n if (attachment.dataUrl) {\n const blob = await (await fetch(attachment.dataUrl)).blob();\n const named = new globalThis.File([blob], fileName, {\n type: blob.type || attachment.mime || '',\n });\n await resource.saveContents(named, { contentType: FileContentType.BINARY });\n } else if (attachment.text != null) {\n await resource.saveContents(attachment.text);\n } else {\n toastError('Attachment has no payload to save');\n return;\n }\n toastInfo(`Saved ${fileName}`);\n } catch (err) {\n toastError(err instanceof Error ? err.message : String(err));\n }\n }\n\n private async addFiles(fileList: FileList | File[]): Promise<void> {\n const files = [...fileList];\n if (!files.length) return;\n\n const sessionId = cognitiveRuntime.ensureSessionId(this.focusedId ?? undefined);\n this.focusedId = sessionId;\n const existing = this.sessionAttachments();\n const accepted: PromptAttachment[] = [];\n\n for (const file of files) {\n if (existing.length + accepted.length >= MAX_ATTACHMENTS) {\n toastError(`At most ${MAX_ATTACHMENTS} files per session`);\n break;\n }\n if (\n existing.some((a) => a.name === file.name && a.byteLength === file.size) ||\n accepted.some((a) => a.name === file.name && a.byteLength === file.size)\n ) {\n continue;\n }\n const result = await readPromptAttachmentFromFile(file);\n if (!result.ok) {\n toastError(result.error);\n continue;\n }\n accepted.push(result.attachment);\n }\n\n const stored = await cognitiveRuntime.addAttachments(sessionId, accepted);\n if (stored.length) {\n this.pendingAttachmentIds = [\n ...this.pendingAttachmentIds,\n ...stored.map((a) => a.id).filter((id) => !this.pendingAttachmentIds.includes(id)),\n ];\n }\n this.syncSessions();\n }\n\n private openFilePicker(): void {\n this.fileInput?.click();\n }\n\n private async onFileInputChange(e: Event): Promise<void> {\n const input = e.target as HTMLInputElement;\n if (input.files?.length) await this.addFiles(input.files);\n input.value = '';\n }\n\n private onComposerDragOver(e: DragEvent): void {\n if (!e.dataTransfer?.types.includes('Files')) return;\n e.preventDefault();\n this.dragOver = true;\n }\n\n private onComposerDragLeave(e: DragEvent): void {\n if (e.currentTarget === e.target) this.dragOver = false;\n }\n\n private async onComposerDrop(e: DragEvent): Promise<void> {\n e.preventDefault();\n this.dragOver = false;\n if (e.dataTransfer?.files?.length) await this.addFiles(e.dataTransfer.files);\n }\n\n /** Attach clipboard files/images (e.g. Ctrl+V screenshot) when focused in the prompt. */\n private async onComposerPaste(e: ClipboardEvent): Promise<void> {\n const files = filesFromClipboard(e.clipboardData);\n if (!files.length) return;\n e.preventDefault();\n await this.addFiles(files);\n }\n\n private cancelTurn(): void {\n if (!this.busy && !this.promptController) return;\n this.promptController?.abort();\n if (this.pendingPermission) this.resolvePermission('deny');\n }\n\n private clearQueuedPrompt(): void {\n this.queuedPrompt = null;\n }\n\n private async queueFollowUp(text: string, attachmentIds: string[]): Promise<void> {\n this.queuedPrompt = { text, attachmentIds };\n this.pendingAttachmentIds = [];\n if (this.fileInput) this.fileInput.value = '';\n await this.setComposerText('');\n }\n\n private async send(): Promise<void> {\n const text = this.draft.trim();\n const attachmentIds = [...this.pendingAttachmentIds];\n if (!text && !attachmentIds.length) return;\n\n // Cursor-like: keep typing during a run; Enter queues a follow-up for after this turn.\n if (this.busy) {\n await this.queueFollowUp(text, attachmentIds);\n return;\n }\n\n this.applyPolicy();\n this.pendingAttachmentIds = [];\n if (this.fileInput) this.fileInput.value = '';\n await this.setComposerText('');\n const controller = new AbortController();\n this.promptController = controller;\n this.busy = true;\n this.streamingParts = [];\n this.startBusyStatus();\n try {\n await cognitiveRuntime.prompt({\n sessionId: this.focusedId ?? undefined,\n text,\n attachmentIds,\n signal: controller.signal,\n });\n } finally {\n if (this.promptController === controller) this.promptController = null;\n this.stopBusyStatus();\n this.busy = false;\n this.streamingParts = [];\n this.syncSessions();\n this.scheduleScrollToBottom();\n const next = this.queuedPrompt;\n this.queuedPrompt = null;\n if (next && (next.text.trim() || next.attachmentIds.length)) {\n this.draft = next.text;\n this.pendingAttachmentIds = next.attachmentIds;\n await this.updateComplete;\n if (this.textarea) this.textarea.value = next.text;\n await this.send();\n return;\n }\n this.textarea?.focus();\n }\n }\n\n private renderAttachmentDropdown() {\n const attachments = this.sessionAttachments();\n const count = attachments.length;\n return html`\n <wa-dropdown class=\"attach-menu\" size=\"s\" placement=\"top-end\" distance=\"4\">\n <wa-button\n slot=\"trigger\"\n size=\"s\"\n appearance=\"plain\"\n title=${count ? `${count} attachment${count === 1 ? '' : 's'}` : 'Attachments'}\n >\n <wa-icon name=\"paperclip\" label=\"Attachments\"></wa-icon>\n ${count > 0 ? html`<wa-badge pill>${count}</wa-badge>` : nothing}\n </wa-button>\n <div\n class=\"attach-panel\"\n @click=${(e: Event) => e.stopPropagation()}\n @keydown=${(e: Event) => e.stopPropagation()}\n >\n ${count\n ? html`\n <div class=\"attach-list\">\n ${attachments.map(\n (file) => html`\n <div class=\"attach-row\">\n <button\n type=\"button\"\n class=\"attach-preview-btn\"\n title=\"Open ${file.name}\"\n @click=${() => this.openAttachmentPreview(file.id)}\n >\n ${file.kind === 'image' && file.dataUrl\n ? html`<img\n class=\"attach-thumb\"\n src=${file.dataUrl}\n alt=${file.name}\n />`\n : html`\n <span class=\"attach-file-icon\">\n <wa-icon name=\"file\" label=\"\"></wa-icon>\n </span>\n `}\n <span class=\"attach-name\">${file.name}</span>\n </button>\n <wa-button\n size=\"s\"\n appearance=\"plain\"\n title=${`Save ${file.name} to workspace folder`}\n @click=${() => void this.saveAttachmentToWorkspace(file.id)}\n >\n <wa-icon name=\"floppy-disk\" label=${`Save ${file.name}`}></wa-icon>\n </wa-button>\n <wa-button\n size=\"s\"\n appearance=\"plain\"\n title=\"Remove from session\"\n @click=${() => this.removeSessionAttachment(file.id)}\n >\n <wa-icon name=\"xmark\" label=\"Remove\"></wa-icon>\n </wa-button>\n </div>\n `,\n )}\n </div>\n `\n : html`<div class=\"attach-empty\">No attachments in this session</div>`}\n <wa-button\n size=\"s\"\n appearance=\"outlined\"\n ?disabled=${count >= MAX_ATTACHMENTS}\n @click=${() => this.openFilePicker()}\n >\n <wa-icon slot=\"start\" name=\"plus\"></wa-icon>\n Add files…\n </wa-button>\n </div>\n </wa-dropdown>\n `;\n }\n\n private renderAttachmentDialog() {\n const preview = this.previewAttachment();\n if (!preview) return nothing;\n return html`\n <wa-dialog\n label=${preview.name}\n open\n light-dismiss\n with-footer\n style=\"--width: min(40rem, 94vw)\"\n @wa-after-hide=${() => this.closeAttachmentPreview()}\n >\n <div class=\"attach-dialog-body\">\n ${preview.kind === 'image' && preview.dataUrl\n ? html`<img class=\"attach-dialog-image\" src=${preview.dataUrl} alt=${preview.name} />`\n : nothing}\n ${preview.text\n ? html`<pre class=\"attach-dialog-text\">${preview.text}</pre>`\n : preview.kind === 'image' && preview.dataUrl\n ? nothing\n : html`<pre class=\"attach-dialog-text\"></pre>`}\n </div>\n <div slot=\"footer\">\n <wa-button\n variant=\"danger\"\n appearance=\"outlined\"\n @click=${() => this.removeSessionAttachment(preview.id)}\n >\n Remove\n </wa-button>\n <wa-button variant=\"brand\" @click=${() => this.closeAttachmentPreview()}>Close</wa-button>\n </div>\n </wa-dialog>\n `;\n }\n\n private openToolDetail(part: Extract<MessagePart, { type: 'tool' }>): void {\n this.toolDetail = part;\n }\n\n private closeToolDetail(): void {\n this.toolDetail = null;\n }\n\n private renderToolDetailDialog() {\n const tool = this.toolDetail;\n if (!tool) return nothing;\n const label = `${tool.name} · ${tool.status}${tool.durationMs != null ? ` · ${tool.durationMs}ms` : ''}`;\n const body = JSON.stringify({ args: tool.args ?? {}, result: tool.result ?? null }, null, 2);\n return html`\n <wa-dialog\n label=${label}\n open\n light-dismiss\n with-footer\n style=\"--width: min(44rem, 96vw)\"\n @wa-after-hide=${() => this.closeToolDetail()}\n >\n <div class=\"tool-detail-body\">\n <pre>${body}</pre>\n </div>\n <div slot=\"footer\">\n <wa-button variant=\"brand\" @click=${() => this.closeToolDetail()}>Close</wa-button>\n </div>\n </wa-dialog>\n `;\n }\n\n private resolvePermission(action: PermissionAction): void {\n if (!this.pendingPermission) return;\n cognitiveRuntime.resolvePermission(this.pendingPermission.requestId, action);\n this.pendingPermission = null;\n }\n\n protected renderToolbar(): TemplateResult {\n const session = this.focusedSession();\n const title = session?.title || 'Chat';\n return html`\n <span class=\"toolbar-title\" title=${title}>${title}</span>\n <wa-button size=\"s\" appearance=\"plain\" title=\"New chat\" @click=${() => this.newSession()}>\n <wa-icon name=\"plus\" label=\"New chat\"></wa-icon>\n </wa-button>\n ${this.renderHistoryDropdown()}\n <wa-button\n size=\"s\"\n appearance=\"plain\"\n title=\"Checkpoint\"\n @click=${() => {\n if (!this.focusedId) return;\n cognitiveRuntime.sessions.checkpoint(this.focusedId);\n this.syncSessions();\n cognitiveRuntime.commitSessions();\n }}\n >\n <wa-icon name=\"floppy-disk\" label=\"Checkpoint\"></wa-icon>\n </wa-button>\n ${this.renderSettingsDropdown()}\n `;\n }\n\n private contextRingStyle(level: ContextUsage['level']): string {\n const tone = level === 'critical' ? 'danger' : level === 'warn' ? 'warning' : 'success';\n // Match Web Awesome docs: quiet track + loud indicator.\n return [\n `--track-color: var(--wa-color-${tone}-fill-quiet)`,\n `--indicator-color: var(--wa-color-${tone}-fill-loud)`,\n ].join(';');\n }\n\n private renderContextDropdown() {\n const usage = this.contextUsage();\n const canCompact = (this.focusedSession()?.history.length ?? 0) > 12;\n const percentLabel = formatContextPercent(usage.percent);\n const title = `Context window ${percentLabel} · ~${formatTokenCount(usage.used)} / ${formatTokenCount(usage.limit)}`;\n const ringValue = Math.min(100, Math.max(usage.percent, usage.used > 0 ? 1 : 0));\n\n return html`\n <wa-dropdown\n class=\"context-menu\"\n size=\"s\"\n placement=\"top-end\"\n distance=\"4\"\n >\n <wa-button\n slot=\"trigger\"\n appearance=\"plain\"\n size=\"s\"\n title=${title}\n >\n <wa-progress-ring\n class=\"context-ring\"\n style=${this.contextRingStyle(usage.level)}\n value=${ringValue}\n label=${title}\n ></wa-progress-ring>\n </wa-button>\n\n <div\n class=\"context-panel\"\n @click=${(e: Event) => e.stopPropagation()}\n @keydown=${(e: Event) => e.stopPropagation()}\n >\n <div class=\"context-header\">\n <strong>Context window</strong>\n <span>${percentLabel}</span>\n </div>\n <div class=\"context-bars\">\n ${usage.buckets.map((bucket) => {\n const share = usage.limit > 0 ? (bucket.tokens / usage.limit) * 100 : 0;\n return html`\n <div class=\"context-row\">\n <span class=\"context-row-label\">${bucket.label}</span>\n <span>${formatBucketDetail(bucket)}</span>\n <div class=\"context-meter\">\n <span\n style=\"width:${Math.max(share, bucket.tokens > 0 ? 0.5 : 0)}%; --bucket-color: var(--wa-color-brand-fill-normal)\"\n ></span>\n </div>\n </div>\n `;\n })}\n </div>\n <div class=\"context-footer\">\n <span class=\"context-remaining\">\n ~${formatTokenCount(usage.used)} in window · ${formatTokenCount(usage.remaining)} free of\n ${formatTokenCount(usage.limit)}\n · ${shortModelLabel(usage.modelRef)}\n </span>\n </div>\n <div\n class=\"context-io\"\n title=\"Sum of provider-reported tokens across every model request in this chat. Each tool-loop call re-sends the prompt, so API input grows much faster than the context window fill.\"\n >\n <div class=\"context-io-heading\">API usage (this chat)</div>\n <div class=\"context-io-item\">\n <span>Input</span>\n <strong>${usage.inputTokens ? formatTokenCount(usage.inputTokens) : '—'}</strong>\n </div>\n <div class=\"context-io-item\">\n <span>Output</span>\n <strong>${usage.outputTokens ? formatTokenCount(usage.outputTokens) : '—'}</strong>\n </div>\n </div>\n <div class=\"context-footer\">\n <wa-button\n size=\"s\"\n variant=${usage.level === 'critical' ? 'danger' : 'neutral'}\n appearance=${canCompact ? 'filled' : 'outlined'}\n ?disabled=${!canCompact || this.busy}\n @click=${() => this.compactFocused()}\n >\n <wa-icon slot=\"start\" name=\"arrows-down-to-line\"></wa-icon>\n Compact conversation\n </wa-button>\n </div>\n </div>\n </wa-dropdown>\n `;\n }\n\n protected renderContent() {\n const session = this.focusedSession();\n return html`\n <div class=\"cognitive-shell\">\n <wa-scroller class=\"transcript\" orientation=\"vertical\">\n <div class=\"transcript-inner\">\n <div class=\"transcript-spacer\" aria-hidden=\"true\"></div>\n ${session ? this.renderTranscript(session) : nothing}\n </div>\n </wa-scroller>\n\n <div\n class=\"composer-shell ${this.dragOver ? 'drag-over' : ''}\"\n @dragover=${(e: DragEvent) => this.onComposerDragOver(e)}\n @dragleave=${(e: DragEvent) => this.onComposerDragLeave(e)}\n @drop=${(e: DragEvent) => void this.onComposerDrop(e)}\n >\n <input\n id=\"attach-file-input\"\n type=\"file\"\n multiple\n accept=${ATTACHMENT_FILE_ACCEPT}\n hidden\n @change=${(e: Event) => void this.onFileInputChange(e)}\n />\n <div class=\"composer\">\n ${this.queuedPrompt\n ? html`\n <div class=\"queued-prompt\" title=\"Sends automatically when the current turn finishes\">\n <wa-icon name=\"clock\"></wa-icon>\n <span class=\"queued-prompt-text\">\n Queued: ${this.queuedPrompt.text.trim() || `(${this.queuedPrompt.attachmentIds.length} attachment${this.queuedPrompt.attachmentIds.length === 1 ? '' : 's'})`}\n </span>\n <wa-button\n size=\"s\"\n appearance=\"plain\"\n title=\"Remove queued follow-up\"\n @click=${() => this.clearQueuedPrompt()}\n >\n <wa-icon name=\"xmark\" label=\"Remove queue\"></wa-icon>\n </wa-button>\n </div>\n `\n : nothing}\n <div class=\"composer-row\">\n <wa-textarea\n placeholder=${this.busy ? 'Add a follow-up…' : 'Enter your message here…'}\n size=\"s\"\n resize=\"auto\"\n rows=\"1\"\n .value=${this.draft}\n @input=${(e: Event) => {\n this.draft = (e.target as HTMLTextAreaElement).value;\n }}\n @keydown=${(e: KeyboardEvent) => {\n if (e.key === 'Escape' && this.busy) {\n e.preventDefault();\n this.cancelTurn();\n return;\n }\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n void this.send();\n }\n }}\n ></wa-textarea>\n <div class=\"composer-actions\">\n ${this.busy\n ? html`\n <wa-button\n size=\"s\"\n appearance=\"plain\"\n variant=\"danger\"\n title=\"Stop (Esc)\"\n @click=${() => this.cancelTurn()}\n >\n <wa-icon name=\"stop\" label=\"Stop\"></wa-icon>\n </wa-button>\n `\n : nothing}\n ${this.renderAttachmentDropdown()}\n ${this.renderContextDropdown()}\n </div>\n </div>\n </div>\n </div>\n ${this.renderAttachmentDialog()}\n ${this.renderToolDetailDialog()}\n </div>\n `;\n }\n\n private renderTranscript(session: CognitiveSession) {\n // Show the live assistant row as soon as the turn starts (busy), not only after\n // the first streamed part — otherwise the transcript stays blank until tools/text arrive.\n const showStreaming = this.busy || this.streamingParts.length > 0;\n const showPermission =\n this.pendingPermission && this.pendingPermission.sessionId === session.id;\n\n return html`\n ${session.history.map((m) => this.renderMessage(m))}\n ${showStreaming\n ? this.renderAssistantMessage(\n {\n id: 'streaming',\n role: 'assistant',\n parts: this.streamingParts,\n createdAt: Date.now(),\n },\n { streaming: true },\n )\n : nothing}\n ${showPermission\n ? html`\n <wa-callout variant=\"warning\" appearance=\"outlined\">\n <wa-icon slot=\"icon\" name=\"shield-halved\"></wa-icon>\n Allow tool <code>${this.pendingPermission!.toolName}</code>?\n <pre class=\"args\">${JSON.stringify(this.pendingPermission!.args, null, 2)}</pre>\n <div class=\"approval-actions\">\n <wa-button size=\"s\" variant=\"success\" @click=${() => this.resolvePermission('allow')}>\n <wa-icon slot=\"start\" name=\"check\"></wa-icon>\n Allow\n </wa-button>\n <wa-button\n size=\"s\"\n variant=\"neutral\"\n appearance=\"outlined\"\n @click=${() => this.resolvePermission('deny')}\n >\n <wa-icon slot=\"start\" name=\"xmark\"></wa-icon>\n Deny\n </wa-button>\n </div>\n </wa-callout>\n `\n : nothing}\n `;\n }\n\n private renderHistoryDropdown() {\n const items = this.historySessions();\n const groups = groupSessionsByRecency(items);\n\n return html`\n <wa-dropdown\n class=\"history-menu\"\n size=\"s\"\n placement=\"bottom-end\"\n distance=\"4\"\n ?open=${this.historyOpen}\n @wa-after-show=${() => {\n this.historyOpen = true;\n }}\n @wa-after-hide=${() => {\n this.historyOpen = false;\n this.historyQuery = '';\n }}\n >\n <wa-button\n slot=\"trigger\"\n appearance=\"plain\"\n size=\"s\"\n with-caret\n title=\"Chat history\"\n @click=${(e: Event) => {\n e.stopPropagation();\n this.historyOpen = !this.historyOpen;\n }}\n >\n <wa-icon name=\"clock-rotate-left\" label=\"Chat history\"></wa-icon>\n </wa-button>\n\n <div\n class=\"history-search\"\n @click=${(e: Event) => e.stopPropagation()}\n @keydown=${(e: Event) => e.stopPropagation()}\n >\n <wa-input\n size=\"s\"\n clearable\n placeholder=\"Search chats…\"\n .value=${this.historyQuery}\n @input=${(e: Event) => {\n this.historyQuery = (e.target as HTMLInputElement).value;\n }}\n >\n <wa-icon slot=\"start\" name=\"magnifying-glass\"></wa-icon>\n </wa-input>\n </div>\n\n ${groups.length\n ? groups.map(\n (group) => html`\n <h3>${group.label}</h3>\n ${group.sessions.map(\n (s) => html`\n <wa-dropdown-item @click=${() => this.openSession(s.id)}>\n <wa-icon\n slot=\"icon\"\n name=${s.id === this.focusedId ? 'check' : 'message'}\n ></wa-icon>\n <span class=\"history-item-title\" title=${s.title}>${s.title}</span>\n <div slot=\"details\" style=\"display:flex;align-items:center;gap:0.25rem\">\n <span class=\"history-item-meta\">${relativeTime(s.updatedAt)}</span>\n <wa-button\n appearance=\"plain\"\n size=\"s\"\n title=\"Delete chat\"\n @click=${(e: Event) => {\n e.stopPropagation();\n this.deleteSession(s.id);\n }}\n >\n <wa-icon name=\"trash\" label=\"Delete chat\"></wa-icon>\n </wa-button>\n </div>\n </wa-dropdown-item>\n `,\n )}\n `,\n )\n : html`<div class=\"history-empty\">${this.historyQuery ? 'No matching chats' : 'No chats yet'}</div>`}\n </wa-dropdown>\n `;\n }\n\n private onSettingsSelect(value: string): void {\n if (value === 'settings') {\n void this.executeCommand(OPEN_AI_SETTINGS_COMMAND, {});\n return;\n }\n if (value.startsWith('approval:')) {\n const mode = value.slice('approval:'.length);\n if (mode === 'manual' || mode === 'auto_safe' || mode === 'auto_all') {\n this.approvalMode = mode;\n cognitiveRuntime.setApprovalMode(mode);\n }\n return;\n }\n if (value.startsWith('effort:')) {\n this.manualEffort = (value.slice(7) as EffortLevel | 'auto') || 'auto';\n this.applyPolicy();\n return;\n }\n this.onRouterSelect(value);\n }\n\n private renderSettingsDropdown() {\n const selected = this.routerValue();\n const autoOptions = [\n { value: 'auto:cost', label: 'Auto · Cost' },\n { value: 'auto:balance', label: 'Auto · Balance' },\n { value: 'auto:intelligence', label: 'Auto · Intelligence' },\n ];\n const effortOptions = this.effortChoices();\n\n return html`\n <wa-dropdown\n class=\"settings-menu\"\n size=\"s\"\n placement=\"bottom-end\"\n distance=\"4\"\n @wa-select=${(e: CustomEvent<{ item?: { value?: string } }>) => {\n const value = e.detail?.item?.value;\n if (value != null) this.onSettingsSelect(value);\n }}\n >\n <wa-button\n slot=\"trigger\"\n appearance=\"plain\"\n size=\"s\"\n with-caret\n title=${`AI · ${this.routerLabel()}`}\n >\n <wa-icon name=\"gear\" label=\"AI settings\"></wa-icon>\n </wa-button>\n\n <h3>Auto</h3>\n ${autoOptions.map(\n (option) => html`\n <wa-dropdown-item\n value=${option.value}\n type=\"checkbox\"\n .checked=${option.value === selected}\n >\n ${option.label}\n </wa-dropdown-item>\n `,\n )}\n\n <wa-divider></wa-divider>\n <h3>Models</h3>\n ${this.modelIds.length\n ? this.modelIds.map(\n (id) => html`\n <wa-dropdown-item\n value=${`model:${id}`}\n type=\"checkbox\"\n .checked=${selected === `model:${id}`}\n >\n ${id}\n </wa-dropdown-item>\n `,\n )\n : html`<wa-dropdown-item disabled>No models configured</wa-dropdown-item>`}\n\n ${this.policyMode === 'manual'\n ? html`\n <wa-divider></wa-divider>\n <h3>Effort</h3>\n ${effortOptions.map(\n (level) => html`\n <wa-dropdown-item\n value=${`effort:${level}`}\n type=\"checkbox\"\n .checked=${this.manualEffort === level}\n >\n ${level}\n </wa-dropdown-item>\n `,\n )}\n `\n : nothing}\n\n <wa-divider></wa-divider>\n <h3>Tool approvals</h3>\n ${APPROVAL_OPTIONS.map(\n (option) => html`\n <wa-dropdown-item\n value=${`approval:${option.value}`}\n type=\"checkbox\"\n .checked=${this.approvalMode === option.value}\n >\n ${option.label}\n </wa-dropdown-item>\n `,\n )}\n\n <wa-divider></wa-divider>\n <wa-dropdown-item value=\"settings\">\n <wa-icon slot=\"icon\" name=\"sliders\"></wa-icon>\n Settings…\n </wa-dropdown-item>\n </wa-dropdown>\n `;\n }\n\n private resolveAttachmentDataUrl(fileId: string): string | undefined {\n return this.focusedSession()?.attachments?.find((a) => a.id === fileId)?.dataUrl;\n }\n\n private renderMessage(message: ChatMessage) {\n if (message.role === 'user') {\n const files = message.parts.filter((p): p is Extract<MessagePart, { type: 'file' }> => p.type === 'file');\n const texts = message.parts.filter((p) => p.type === 'text');\n return html`\n <div class=\"msg user\">\n ${files.length\n ? html`\n <div class=\"msg-files\">\n ${files.map((file) => {\n const dataUrl =\n file.kind === 'image' ? this.resolveAttachmentDataUrl(file.id) : undefined;\n return dataUrl\n ? html`<img\n class=\"msg-file-thumb\"\n src=${dataUrl}\n alt=${file.name}\n title=${`${file.name} (${file.id})`}\n />`\n : html`\n <wa-tag\n size=\"s\"\n appearance=\"outlined\"\n title=${`${file.path || file.name} (${file.id})`}\n >\n <wa-icon slot=\"start\" name=${file.kind === 'image' ? 'image' : 'file'}></wa-icon>\n ${file.name}\n </wa-tag>\n `;\n })}\n </div>\n `\n : nothing}\n ${texts.map((p) => this.renderTextPart(p))}\n ${this.renderMessageMeta(message)}\n </div>\n `;\n }\n return this.renderAssistantMessage(message);\n }\n\n private renderAssistantMessage(message: ChatMessage, opts: { streaming?: boolean } = {}) {\n const { summaryText, techParts } = splitAssistantPresentation(message.parts);\n const open =\n opts.streaming === true ||\n techParts.some((p) => (p.type === 'reasoning' || p.type === 'tool') && p.status === 'streaming');\n\n const summaryBubble = summaryText.length\n ? summaryText.map((p) => this.renderTextPart(p, { markdown: true }))\n : opts.streaming\n ? nothing\n : html`<div class=\"bubble\">${technicalSummary(techParts)}</div>`;\n\n const summary = html`\n <div slot=\"summary\" class=\"msg-summary\">\n ${opts.streaming\n ? html`\n <div class=\"streaming-meta\">\n <wa-spinner style=\"font-size: 0.85rem\"></wa-spinner>\n <span>${this.busy ? this.busyStatus : 'streaming…'}</span>\n </div>\n `\n : nothing}\n ${summaryBubble}\n </div>\n `;\n\n if (!techParts.length) {\n return html`\n <div class=\"msg assistant\">\n ${opts.streaming\n ? html`\n <div class=\"streaming-meta\">\n <wa-spinner style=\"font-size: 0.85rem\"></wa-spinner>\n <span>${this.busy ? this.busyStatus : 'streaming…'}</span>\n </div>\n `\n : nothing}\n ${summaryBubble}\n ${message.id !== 'streaming' ? this.renderMessageMeta(message) : nothing}\n </div>\n `;\n }\n\n return html`\n <div class=\"msg assistant\">\n <wa-details class=\"msg-details\" appearance=\"plain\" ?open=${open}>\n ${summary}\n <div class=\"msg-tech\">${techParts.map((p) => this.renderTechnicalPart(p))}</div>\n </wa-details>\n ${message.id !== 'streaming' ? this.renderMessageMeta(message) : nothing}\n </div>\n `;\n }\n\n private renderMessageMeta(message: ChatMessage) {\n const timeLabel = formatMessageTime(message.createdAt);\n return html`\n <div class=\"msg-meta\">\n <wa-tag size=\"s\" appearance=\"outlined\" title=${new Date(message.createdAt).toLocaleString()}>\n ${timeLabel}\n </wa-tag>\n ${message.routedModel\n ? html`<wa-tag size=\"s\" appearance=\"outlined\">${message.routedModel}</wa-tag>`\n : nothing}\n ${message.effort\n ? html`<wa-tag size=\"s\" appearance=\"outlined\">${message.effort}</wa-tag>`\n : nothing}\n </div>\n `;\n }\n\n private renderTextPart(part: MessagePart, opts: { markdown?: boolean } = {}) {\n if (part.type !== 'text') return nothing;\n if (opts.markdown) {\n return html`<div class=\"bubble markdown\">${unsafeHTML(parseMarkdownHtml(part.text))}</div>`;\n }\n return html`<div class=\"bubble\">${part.text}</div>`;\n }\n\n private renderTechnicalPart(part: MessagePart) {\n if (part.type === 'reasoning') {\n return html`\n <div>\n <div class=\"tool-heading\">Thinking</div>\n <div class=\"bubble\">${part.text}</div>\n </div>\n `;\n }\n if (part.type === 'tool') {\n const heading = `${part.name} · ${part.status}${part.durationMs != null ? ` · ${part.durationMs}ms` : ''}`;\n const hasDetail = part.args != null || part.result != null || part.status === 'error';\n return html`\n <div class=\"tool-row\">\n <div class=\"tool-heading\">${heading}</div>\n ${hasDetail\n ? html`\n <wa-button\n size=\"s\"\n appearance=\"plain\"\n variant=\"neutral\"\n @click=${() => this.openToolDetail(part)}\n >\n Details\n </wa-button>\n `\n : nothing}\n </div>\n `;\n }\n if (part.type === 'step') {\n return html`<div class=\"tool-heading\">Step: ${part.title} · ${part.status}</div>`;\n }\n return nothing;\n }\n}\n\nconst APPROVAL_OPTIONS: Array<{ value: ToolApprovalMode; label: string }> = [\n { value: 'auto_safe', label: 'Auto-approve non-critical' },\n { value: 'manual', label: 'Manual' },\n { value: 'auto_all', label: 'Approve all' },\n];\n\nfunction capitalize(value: string): string {\n return value ? value[0]!.toUpperCase() + value.slice(1) : value;\n}\n\n/** Basename used when saving an attachment into a workspace folder. */\nfunction attachmentSaveFileName(attachment: SessionAttachment): string {\n const fromName = attachment.name.trim().split(/[/\\\\]/).pop()?.trim();\n if (fromName) return fromName;\n const fromPath = attachment.path?.split(/[/\\\\]/).pop()?.trim();\n if (fromPath) return fromPath;\n if (attachment.kind === 'image') {\n return attachment.mime === 'image/jpeg' ? 'attachment.jpg' : 'attachment.png';\n }\n return 'attachment.txt';\n}\n\n/** `photo.png` → `photo (1).png`, `photo (2).png`, … when the path is taken. */\nfunction withNumericSuffix(fileName: string, n: number): string {\n const dot = fileName.lastIndexOf('.');\n if (dot > 0) {\n return `${fileName.slice(0, dot)} (${n})${fileName.slice(dot)}`;\n }\n return `${fileName} (${n})`;\n}\n\nasync function uniqueWorkspaceFileName(\n workspace: { getResource(path: string): Promise<unknown> },\n parentPath: string,\n fileName: string,\n): Promise<string> {\n const candidatePath = (name: string) => `${parentPath}/${name}`;\n if (!(await workspace.getResource(candidatePath(fileName)))) return fileName;\n for (let n = 1; n < 10_000; n++) {\n const next = withNumericSuffix(fileName, n);\n if (!(await workspace.getResource(candidatePath(next)))) return next;\n }\n return withNumericSuffix(fileName, Date.now());\n}\n\n/**\n * Prefer text after the last tool/reasoning as the visible reply.\n * Interim narration stays out of the bubble — tool details cover the execution trail.\n */\nfunction splitAssistantPresentation(parts: MessagePart[]): {\n summaryText: Array<Extract<MessagePart, { type: 'text' }>>;\n techParts: MessagePart[];\n} {\n const techParts = parts.filter((p) => p.type !== 'text');\n let lastTechIndex = -1;\n for (let i = 0; i < parts.length; i++) {\n if (parts[i]!.type !== 'text') lastTechIndex = i;\n }\n\n if (lastTechIndex < 0) {\n return {\n summaryText: parts.filter((p): p is Extract<MessagePart, { type: 'text' }> => p.type === 'text'),\n techParts,\n };\n }\n\n const afterTools = parts\n .slice(lastTechIndex + 1)\n .filter((p): p is Extract<MessagePart, { type: 'text' }> => p.type === 'text')\n .filter((p) => p.text.trim());\n\n if (afterTools.length) {\n return { summaryText: afterTools, techParts };\n }\n\n // Tools ran but no trailing reply yet (streaming) — keep the bubble light.\n return { summaryText: [], techParts };\n}\n\nfunction technicalSummary(parts: MessagePart[]): string {\n const tools = parts.filter((p): p is Extract<MessagePart, { type: 'tool' }> => p.type === 'tool');\n const done = tools.filter((t) => t.status === 'done').length;\n const errors = tools.filter((t) => t.status === 'error').length;\n if (!tools.length) {\n if (parts.some((p) => p.type === 'reasoning')) return 'Thinking…';\n return 'Details';\n }\n if (errors && done) return `Finished with ${errors} issue${errors === 1 ? '' : 's'} (${done} ok).`;\n if (errors) return `Couldn't complete ${errors} step${errors === 1 ? '' : 's'}.`;\n if (tools.some((t) => t.status === 'running' || t.status === 'preparing')) {\n return 'Working…';\n }\n return done === 1 ? 'Done.' : `Done · ${done} steps.`;\n}\n\nfunction startOfDay(ts: number): number {\n const d = new Date(ts);\n d.setHours(0, 0, 0, 0);\n return d.getTime();\n}\n\nfunction groupSessionsByRecency(sessions: CognitiveSession[]): Array<{ label: string; sessions: CognitiveSession[] }> {\n const now = Date.now();\n const today = startOfDay(now);\n const yesterday = today - 86_400_000;\n const week = today - 7 * 86_400_000;\n const buckets: Record<'today' | 'yesterday' | 'week' | 'older', CognitiveSession[]> = {\n today: [],\n yesterday: [],\n week: [],\n older: [],\n };\n\n for (const s of sessions) {\n const day = startOfDay(s.updatedAt);\n if (day >= today) buckets.today.push(s);\n else if (day >= yesterday) buckets.yesterday.push(s);\n else if (day >= week) buckets.week.push(s);\n else buckets.older.push(s);\n }\n\n return (\n [\n { label: 'Today', sessions: buckets.today },\n { label: 'Yesterday', sessions: buckets.yesterday },\n { label: 'Previous 7 Days', sessions: buckets.week },\n { label: 'Older', sessions: buckets.older },\n ] as const\n ).filter((g) => g.sessions.length > 0);\n}\n\nfunction relativeTime(ts: number): string {\n const delta = Math.max(0, Date.now() - ts);\n const mins = Math.floor(delta / 60_000);\n if (mins < 1) return 'now';\n if (mins < 60) return `${mins}m`;\n const hours = Math.floor(mins / 60);\n if (hours < 24) return `${hours}h`;\n const days = Math.floor(hours / 24);\n if (days < 7) return `${days}d`;\n return new Date(ts).toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n}\n\nfunction formatMessageTime(ts: number): string {\n const date = new Date(ts);\n const now = new Date();\n const sameDay =\n date.getFullYear() === now.getFullYear() &&\n date.getMonth() === now.getMonth() &&\n date.getDate() === now.getDate();\n const time = date.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });\n if (sameDay) return time;\n return `${date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })} ${time}`;\n}\n\nfunction shortModelLabel(modelRef: string): string {\n const slash = modelRef.indexOf('/');\n return slash === -1 ? modelRef : modelRef.slice(slash + 1);\n}\n\nfunction filesFromClipboard(data: DataTransfer | null): File[] {\n if (!data) return [];\n\n const fromFiles = [...(data.files ?? [])].filter((f) => f && f.size > 0);\n if (fromFiles.length) return fromFiles;\n\n const fromItems: File[] = [];\n for (const item of data.items ?? []) {\n if (item.kind !== 'file') continue;\n const file = item.getAsFile();\n if (!file || file.size <= 0) continue;\n fromItems.push(nameClipboardFile(file, item.type));\n }\n return fromItems;\n}\n\nfunction nameClipboardFile(file: File, mimeHint?: string): File {\n const mime = (file.type || mimeHint || 'application/octet-stream').toLowerCase();\n if (file.name && file.name !== 'image.png' && file.name !== 'blob') return file;\n const ext =\n mime === 'image/jpeg' || mime === 'image/jpg'\n ? 'jpg'\n : mime === 'image/png'\n ? 'png'\n : mime === 'image/gif'\n ? 'gif'\n : mime === 'image/webp'\n ? 'webp'\n : mime === 'image/svg+xml'\n ? 'svg'\n : mime.startsWith('image/')\n ? 'png'\n : 'bin';\n const name = `clipboard-${Date.now()}.${ext}`;\n return new File([file], name, { type: mime || file.type, lastModified: file.lastModified });\n}\n\nfunction mergePart(parts: MessagePart[], part: MessagePart): MessagePart[] {\n const next = [...parts];\n const last = next[next.length - 1];\n if (part.type === 'text' && last?.type === 'text') {\n next[next.length - 1] = { ...last, text: last.text + part.text };\n return next;\n }\n if (part.type === 'reasoning' && last?.type === 'reasoning') {\n next[next.length - 1] = { ...last, text: last.text + part.text, status: part.status };\n return next;\n }\n if (part.type === 'tool' && last?.type === 'tool' && last.id === part.id) {\n next[next.length - 1] = part;\n return next;\n }\n next.push(part);\n return next;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'docks-cognitive-view': DocksCognitiveView;\n }\n}\n","import '@eclipse-docks/core/externals/webawesome';\nimport {\n DocksPart,\n EditorInput,\n confirmDialog,\n toastError,\n toastInfo,\n} from '@eclipse-docks/core';\nimport { css, customElement, html, property, state } from '@eclipse-docks/core/externals/lit';\nimport {\n cognitiveRuntime,\n TOPIC,\n defaultProvidersSettings,\n fetchOpenAICompatibleModels,\n parseModelIds,\n} from '../runtime';\nimport type { ProviderConfig, ProvidersSettings, RemoteModelInfo, ToolApprovalMode } from '../runtime';\n\nconst APPROVAL_OPTIONS: Array<{ value: ToolApprovalMode; label: string; hint: string }> = [\n {\n value: 'auto_safe',\n label: 'Auto-approve non-critical',\n hint: 'The agent classifies each tool as safe or critical; only critical ones ask for approval',\n },\n { value: 'manual', label: 'Manual', hint: 'Confirm every tool before it runs' },\n { value: 'auto_all', label: 'Approve all', hint: 'Run every tool without asking' },\n];\n\n@customElement('docks-cognitive-settings-editor')\nexport class DocksCognitiveSettingsEditor extends DocksPart {\n @property({ attribute: false }) public input?: EditorInput;\n\n @state() private settings: ProvidersSettings = defaultProvidersSettings();\n @state() private approvalMode: ToolApprovalMode = 'auto_safe';\n @state() private availableModels: Record<number, RemoteModelInfo[]> = {};\n @state() private loadingModels: Record<number, boolean> = {};\n @state() private modelErrors: Record<number, string> = {};\n\n private unsubs: Array<() => void> = [];\n private fetchControllers = new Map<number, AbortController>();\n private fetchTimers = new Map<number, ReturnType<typeof setTimeout>>();\n private autoFetchedKeys = new Set<string>();\n\n protected doInitUI(): void {\n cognitiveRuntime.start();\n this.loadFromRuntime();\n this.unsubs.push(\n cognitiveRuntime.events.subscribe(TOPIC.providersChanged, () => {\n if (!this.isDirty()) this.loadFromRuntime();\n }),\n cognitiveRuntime.events.subscribe(TOPIC.approvalModeChanged, (mode) => {\n this.approvalMode = mode as ToolApprovalMode;\n }),\n );\n }\n\n disconnectedCallback(): void {\n for (const unsub of this.unsubs) unsub();\n this.unsubs = [];\n for (const timer of this.fetchTimers.values()) clearTimeout(timer);\n this.fetchTimers.clear();\n for (const controller of this.fetchControllers.values()) controller.abort();\n this.fetchControllers.clear();\n super.disconnectedCallback();\n }\n\n private loadFromRuntime(): void {\n this.settings = cognitiveRuntime.getProvidersSettings();\n this.approvalMode = cognitiveRuntime.getApprovalMode();\n this.availableModels = {};\n this.loadingModels = {};\n this.modelErrors = {};\n this.autoFetchedKeys.clear();\n this.markDirty(false);\n this.settings.providers.forEach((provider, index) => {\n if (provider.apiKey.trim() && provider.baseUrl.trim()) {\n void this.fetchModels(index, { auto: true });\n }\n });\n }\n\n private setApprovalMode(mode: ToolApprovalMode): void {\n this.approvalMode = mode;\n cognitiveRuntime.setApprovalMode(mode);\n }\n\n private touch(next: ProvidersSettings): void {\n this.settings = next;\n this.markDirty(true);\n }\n\n private updateProvider(index: number, patch: Partial<ProviderConfig>): void {\n const prev = this.settings.providers[index];\n const providers = this.settings.providers.map((p, i) => (i === index ? { ...p, ...patch } : p));\n let defaultProviderId = this.settings.defaultProviderId;\n if (patch.id && prev?.id === defaultProviderId) {\n defaultProviderId = patch.id;\n }\n this.touch({ ...this.settings, defaultProviderId, providers });\n\n if (patch.apiKey !== undefined || patch.baseUrl !== undefined) {\n const next = providers[index];\n if (next?.apiKey.trim() && next.baseUrl.trim()) {\n this.scheduleFetchModels(index);\n } else if (!next?.apiKey.trim()) {\n this.clearModels(index);\n }\n }\n }\n\n private clearModels(index: number): void {\n this.fetchTimers.get(index) && clearTimeout(this.fetchTimers.get(index)!);\n this.fetchTimers.delete(index);\n this.fetchControllers.get(index)?.abort();\n this.fetchControllers.delete(index);\n const { [index]: _a, ...available } = this.availableModels;\n const { [index]: _b, ...loading } = this.loadingModels;\n const { [index]: _c, ...errors } = this.modelErrors;\n this.availableModels = available;\n this.loadingModels = loading;\n this.modelErrors = errors;\n }\n\n private scheduleFetchModels(index: number): void {\n const existing = this.fetchTimers.get(index);\n if (existing) clearTimeout(existing);\n this.fetchTimers.set(\n index,\n setTimeout(() => {\n this.fetchTimers.delete(index);\n void this.fetchModels(index, { auto: true });\n }, 400),\n );\n }\n\n private async fetchModels(index: number, opts: { auto?: boolean } = {}): Promise<void> {\n const provider = this.settings.providers[index];\n if (!provider?.baseUrl.trim()) {\n toastError('Set a base URL before fetching models');\n return;\n }\n if (opts.auto && !provider.apiKey.trim()) return;\n\n const fingerprint = `${provider.baseUrl}|${provider.apiKey}`;\n if (opts.auto && this.autoFetchedKeys.has(fingerprint) && this.availableModels[index]?.length) {\n return;\n }\n\n this.fetchControllers.get(index)?.abort();\n const controller = new AbortController();\n this.fetchControllers.set(index, controller);\n this.loadingModels = { ...this.loadingModels, [index]: true };\n this.modelErrors = { ...this.modelErrors, [index]: '' };\n\n try {\n const models = await fetchOpenAICompatibleModels(\n provider.baseUrl,\n provider.apiKey || undefined,\n controller.signal,\n );\n if (controller.signal.aborted) return;\n this.availableModels = { ...this.availableModels, [index]: models };\n this.autoFetchedKeys.add(fingerprint);\n if (!opts.auto) toastInfo(`Loaded ${models.length} models`);\n } catch (err) {\n if (controller.signal.aborted) return;\n const message = err instanceof Error ? err.message : String(err);\n this.modelErrors = { ...this.modelErrors, [index]: message };\n this.availableModels = { ...this.availableModels, [index]: [] };\n if (!opts.auto) toastError(message);\n } finally {\n if (this.fetchControllers.get(index) === controller) {\n this.fetchControllers.delete(index);\n this.loadingModels = { ...this.loadingModels, [index]: false };\n }\n }\n }\n\n private onModelsSelect(index: number, e: Event): void {\n const target = e.target as HTMLSelectElement & { value: string | string[] };\n const value = target.value;\n const selected = Array.isArray(value) ? value : value ? [value] : [];\n this.updateProvider(index, { models: selected.join(',') });\n }\n\n private addProvider(): void {\n const id = uniqueProviderId(this.settings.providers);\n this.touch({\n ...this.settings,\n providers: [\n ...this.settings.providers,\n { id, baseUrl: '', apiKey: '', models: '', enabled: true },\n ],\n defaultProviderId: this.settings.defaultProviderId || id,\n });\n }\n\n private async deleteProvider(index: number): Promise<void> {\n const provider = this.settings.providers[index];\n if (!provider) return;\n if (!(await confirmDialog(`Delete provider \"${provider.id || '(unnamed)'}\"?`))) return;\n this.clearModels(index);\n const providers = this.settings.providers.filter((_, i) => i !== index);\n const defaultProviderId =\n this.settings.defaultProviderId === provider.id\n ? (providers.find((p) => p.enabled)?.id ?? '')\n : this.settings.defaultProviderId;\n this.touch({ providers, defaultProviderId });\n this.reindexModelState(index);\n }\n\n /** Shift per-row model fetch state after a row is removed. */\n private reindexModelState(removed: number): void {\n const remap = <T,>(src: Record<number, T>): Record<number, T> => {\n const next: Record<number, T> = {};\n for (const [key, value] of Object.entries(src)) {\n const i = Number(key);\n if (Number.isNaN(i) || i === removed) continue;\n next[i > removed ? i - 1 : i] = value;\n }\n return next;\n };\n this.availableModels = remap(this.availableModels);\n this.loadingModels = remap(this.loadingModels);\n this.modelErrors = remap(this.modelErrors);\n }\n\n private setDefault(id: string): void {\n this.touch({ ...this.settings, defaultProviderId: id });\n }\n\n override async save(): Promise<void> {\n if (!this.isDirty()) return;\n try {\n await cognitiveRuntime.setProvidersSettings(this.settings);\n this.loadFromRuntime();\n toastInfo('AI providers saved');\n } catch (err) {\n toastError(err instanceof Error ? err.message : String(err));\n }\n }\n\n protected renderContent() {\n const rows = this.settings.providers;\n return html`\n <div class=\"editor\">\n <section class=\"section\">\n <header class=\"header\">\n <div>\n <h2>AI Providers</h2>\n <p class=\"hint\">OpenAI-compatible endpoints. Edit cells in place, then save from the toolbar.</p>\n </div>\n <wa-button size=\"s\" variant=\"brand\" appearance=\"filled\" @click=${() => this.addProvider()}>\n <wa-icon slot=\"start\" name=\"plus\"></wa-icon>\n Add provider\n </wa-button>\n </header>\n\n ${rows.length === 0\n ? html`<wa-callout variant=\"neutral\" appearance=\"outlined\">No providers configured.</wa-callout>`\n : html`\n <div class=\"table-wrap\">\n <table class=\"providers\">\n <thead>\n <tr>\n <th class=\"col-on\">On</th>\n <th class=\"col-id\">ID</th>\n <th class=\"col-url\">Base URL</th>\n <th class=\"col-key\">API Key</th>\n <th class=\"col-models\">Models</th>\n <th class=\"col-default\">Default</th>\n <th class=\"col-actions\"></th>\n </tr>\n </thead>\n <tbody>\n ${rows.map((provider, index) => this.renderRow(provider, index))}\n </tbody>\n </table>\n </div>\n `}\n\n <wa-callout variant=\"neutral\" appearance=\"plain\" size=\"s\">\n <wa-icon slot=\"icon\" name=\"circle-info\"></wa-icon>\n Enter an API key to load available models. Catalog ids become\n <code>providerId/modelId</code> for Auto routing.\n </wa-callout>\n </section>\n\n <section class=\"section\">\n <header class=\"header\">\n <div>\n <h2>Tool approvals</h2>\n <p class=\"hint\">How the agent handles tool confirmation — same options as GitHub Copilot.</p>\n </div>\n </header>\n <wa-radio-group\n name=\"approval-mode\"\n label=\"Approval mode\"\n orientation=\"vertical\"\n .value=${this.approvalMode}\n @change=${(e: Event) => {\n const value = (e.target as HTMLInputElement).value;\n if (value === 'manual' || value === 'auto_safe' || value === 'auto_all') {\n this.setApprovalMode(value);\n }\n }}\n >\n ${APPROVAL_OPTIONS.map(\n (option) => html`\n <wa-radio value=${option.value}>\n <span class=\"approval-option\">\n <span class=\"approval-label\">${option.label}</span>\n <span class=\"approval-hint\">${option.hint}</span>\n </span>\n </wa-radio>\n `,\n )}\n </wa-radio-group>\n </section>\n </div>\n `;\n }\n\n private renderRow(provider: ProviderConfig, index: number) {\n const isDefault = this.settings.defaultProviderId === provider.id;\n return html`\n <tr class=${isDefault ? 'is-default' : ''}>\n <td>\n <wa-checkbox\n ?checked=${provider.enabled}\n @change=${(e: Event) =>\n this.updateProvider(index, { enabled: (e.target as HTMLInputElement).checked })}\n ></wa-checkbox>\n </td>\n <td>\n <wa-input\n size=\"s\"\n .value=${provider.id}\n placeholder=\"openai\"\n @input=${(e: Event) => this.updateProvider(index, { id: (e.target as HTMLInputElement).value })}\n ></wa-input>\n </td>\n <td>\n <wa-input\n size=\"s\"\n .value=${provider.baseUrl}\n placeholder=\"https://api.openai.com/v1\"\n @input=${(e: Event) =>\n this.updateProvider(index, { baseUrl: (e.target as HTMLInputElement).value })}\n ></wa-input>\n </td>\n <td>\n <wa-input\n size=\"s\"\n type=\"password\"\n password-toggle\n .value=${provider.apiKey}\n placeholder=\"optional\"\n @input=${(e: Event) =>\n this.updateProvider(index, { apiKey: (e.target as HTMLInputElement).value })}\n ></wa-input>\n </td>\n <td>${this.renderModelsCell(provider, index)}</td>\n <td class=\"col-default\">\n ${isDefault\n ? html`<wa-tag size=\"s\" variant=\"brand\" pill>Default</wa-tag>`\n : html`\n <wa-button\n size=\"s\"\n appearance=\"plain\"\n ?disabled=${!provider.id}\n @click=${() => this.setDefault(provider.id)}\n >\n Set\n </wa-button>\n `}\n </td>\n <td class=\"col-actions\">\n <wa-button\n size=\"s\"\n appearance=\"plain\"\n variant=\"danger\"\n title=\"Delete\"\n @click=${() => void this.deleteProvider(index)}\n >\n <wa-icon name=\"trash\" label=\"Delete\"></wa-icon>\n </wa-button>\n </td>\n </tr>\n `;\n }\n\n private renderModelsCell(provider: ProviderConfig, index: number) {\n const hasKey = Boolean(provider.apiKey.trim());\n const remote = this.availableModels[index] ?? [];\n const loading = Boolean(this.loadingModels[index]);\n const error = this.modelErrors[index];\n const selected = parseModelIds(provider.models);\n const showPicker = hasKey || remote.length > 0;\n\n if (!showPicker) {\n return html`\n <div class=\"models-cell\">\n <wa-input\n size=\"s\"\n .value=${provider.models}\n placeholder=\"gpt-4o-mini,gpt-4o\"\n @input=${(e: Event) =>\n this.updateProvider(index, { models: (e.target as HTMLInputElement).value })}\n ></wa-input>\n <wa-button\n size=\"s\"\n appearance=\"plain\"\n title=\"Fetch models\"\n ?disabled=${!provider.baseUrl.trim() || loading}\n ?loading=${loading}\n @click=${() => void this.fetchModels(index)}\n >\n <wa-icon name=\"arrows-rotate\" label=\"Reload models\"></wa-icon>\n </wa-button>\n </div>\n `;\n }\n\n return html`\n <div class=\"models-cell\">\n <wa-select\n size=\"s\"\n multiple\n with-clear\n placeholder=${loading ? 'Loading models…' : 'Select models'}\n .value=${selected}\n ?disabled=${loading && remote.length === 0}\n @change=${(e: Event) => this.onModelsSelect(index, e)}\n >\n ${remote.map(\n (m) => html`<wa-option value=${m.id}>${m.name === m.id ? m.id : `${m.name} (${m.id})`}</wa-option>`,\n )}\n ${selected\n .filter((id) => !remote.some((m) => m.id === id))\n .map((id) => html`<wa-option value=${id}>${id}</wa-option>`)}\n </wa-select>\n <wa-button\n size=\"s\"\n appearance=\"plain\"\n title=\"Reload models\"\n ?disabled=${!provider.baseUrl.trim() || loading}\n ?loading=${loading}\n @click=${() => void this.fetchModels(index)}\n >\n <wa-icon name=\"arrows-rotate\" label=\"Reload models\"></wa-icon>\n </wa-button>\n </div>\n ${error ? html`<div class=\"models-error\">${error}</div>` : ''}\n `;\n }\n\n static styles = css`\n :host {\n display: block;\n height: 100%;\n }\n\n .editor {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-2xl);\n padding: var(--wa-space-l);\n min-width: 0;\n }\n\n .section {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-l);\n min-width: 0;\n }\n\n .header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: var(--wa-space-m);\n flex-wrap: wrap;\n }\n\n .header h2 {\n margin: 0;\n font-size: var(--wa-font-size-l);\n }\n\n wa-radio-group {\n max-width: 36rem;\n }\n\n .approval-option {\n display: flex;\n flex-direction: column;\n gap: var(--wa-space-3xs);\n padding-block: var(--wa-space-3xs);\n }\n\n .approval-label {\n font-weight: 500;\n }\n\n .approval-hint {\n color: var(--wa-color-text-quiet);\n font-size: var(--wa-font-size-s);\n }\n\n .hint {\n margin: var(--wa-space-2xs) 0 0;\n color: var(--wa-color-text-quiet);\n font-size: var(--wa-font-size-s);\n }\n\n .table-wrap {\n overflow: auto;\n border: var(--wa-border-width-s) solid var(--wa-color-border-normal);\n border-radius: var(--wa-border-radius-m);\n }\n\n table.providers {\n width: 100%;\n border-collapse: collapse;\n min-width: 56rem;\n }\n\n th,\n td {\n padding: var(--wa-space-2xs) var(--wa-space-s);\n border-bottom: var(--wa-border-width-s) solid var(--wa-color-border-normal);\n text-align: left;\n vertical-align: middle;\n }\n\n th {\n font-size: var(--wa-font-size-xs);\n font-weight: 600;\n color: var(--wa-color-text-quiet);\n background: var(--wa-color-surface-lowered);\n white-space: nowrap;\n }\n\n tr.is-default td {\n background: color-mix(in srgb, var(--wa-color-brand-fill-normal) 8%, transparent);\n }\n\n tbody tr:last-child td {\n border-bottom: none;\n }\n\n .col-on {\n width: 2.5rem;\n }\n\n .col-id {\n width: 8rem;\n }\n\n .col-key {\n width: 11rem;\n }\n\n .col-models {\n min-width: 16rem;\n }\n\n .col-default {\n width: 5.5rem;\n white-space: nowrap;\n }\n\n .col-actions {\n width: 2.75rem;\n text-align: end;\n }\n\n td wa-input {\n width: 100%;\n }\n\n .models-cell {\n display: flex;\n gap: var(--wa-space-2xs);\n align-items: flex-start;\n min-width: 14rem;\n }\n\n .models-cell wa-input,\n .models-cell wa-select {\n flex: 1;\n min-width: 0;\n }\n\n .models-error {\n margin-top: var(--wa-space-3xs);\n color: var(--wa-color-danger-on-quiet);\n font-size: var(--wa-font-size-xs);\n }\n\n code {\n font-family: var(--wa-font-family-code, var(--wa-font-mono));\n font-size: 0.9em;\n }\n `;\n}\n\nfunction uniqueProviderId(existing: ProviderConfig[]): string {\n const used = new Set(existing.map((p) => p.id));\n if (!used.has('provider')) return 'provider';\n let n = 2;\n while (used.has(`provider-${n}`)) n += 1;\n return `provider-${n}`;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'docks-cognitive-settings-editor': DocksCognitiveSettingsEditor;\n }\n}\n","import {\n contributionRegistry,\n editorRegistry,\n registerAll,\n rootContext,\n SIDEBAR_AUXILIARY,\n type EditorInput,\n} from '@eclipse-docks/core';\nimport { html } from '@eclipse-docks/core/externals/lit';\nimport {\n AI_SETTINGS_EDITOR_ID,\n AI_SETTINGS_KEY,\n AI_VIEW_NAME,\n OPEN_AI_SETTINGS_COMMAND,\n cognitiveRuntime,\n registerSkillCommands,\n} from './runtime';\nimport './view/cognitive-view';\nimport './view/cognitive-settings-editor';\n\ncognitiveRuntime.start();\nregisterSkillCommands();\nrootContext.put('cognitiveRuntime', cognitiveRuntime);\n\ncontributionRegistry.registerContribution(SIDEBAR_AUXILIARY, {\n name: AI_VIEW_NAME,\n label: 'AI',\n icon: 'robot',\n editorId: AI_VIEW_NAME,\n component: (id: string) => html`<docks-cognitive-view id=\"${id}\"></docks-cognitive-view>`,\n});\n\neditorRegistry.registerEditorInputHandler({\n editorId: AI_SETTINGS_EDITOR_ID,\n label: 'AI Settings',\n ranking: 1000,\n canHandle: (input: EditorInput) => input.key === AI_SETTINGS_KEY,\n handle: async (input: EditorInput) => {\n input.component = (id: string) =>\n html`<docks-cognitive-settings-editor id=\"${id}\" .input=${input}></docks-cognitive-settings-editor>`;\n return input;\n },\n});\n\nregisterAll({\n command: {\n id: OPEN_AI_SETTINGS_COMMAND,\n name: 'Open AI Settings',\n description: 'Configure AI model providers',\n parameters: [],\n },\n handler: {\n execute: () => {\n const editorInput = {\n title: 'AI Settings',\n data: {},\n key: AI_SETTINGS_KEY,\n icon: 'gear',\n state: {},\n } as EditorInput;\n void editorRegistry.loadEditor(editorInput);\n },\n },\n});\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ extensionRegistry.registerExtension({
9
9
  id: pkg.name,
10
10
  name: t.EXT_COGNITIVE_NAME,
11
11
  description: t.EXT_COGNITIVE_DESC,
12
- loader: () => import("./cognitive-extension-BKGxwLYj.js"),
12
+ loader: () => import("./cognitive-extension-CvP05Bw_.js"),
13
13
  icon: "robot"
14
14
  });
15
15
  //#endregion
@@ -2643,7 +2643,7 @@ function systemPromptFor(role, goal, opts = {}) {
2643
2643
  "This turn publishes session attachments under the shared in-memory root (in-memory/<sessionId>/… or in-memory://<sessionId>/…).",
2644
2644
  "Read them with workspace_read / workspace_list — in-memory paths work without mounting that root into the workspace tree.",
2645
2645
  "Do not call load_workspace / connect_opfs / connect_indexeddb to find attachments.",
2646
- "Canvas from a screenshot: skills.load eclipse-docks-canvas → workspace_read the attachment path → workspace_write a .canvas.js (into a durable workspace folder) → canvas.open / canvas.apply_source.",
2646
+ "Canvas from a screenshot: skills.load eclipse-docks-canvas → workspace_read the attachment path → workspace_write a new .canvas.js (into a durable workspace folder) → canvas.open. Change a canvas with canvas.apply_source. An open editor is marked dirty and recompiled and is not saved; a canvas that is not open in an editor is written to its file. Do not workspace_write a canvas that is already open.",
2647
2647
  "Qualify durable writes as <root>/<file> using a root from workspace_list (e.g. tests/demo.canvas.js); bare filenames are auto-rooted when a single durable folder is connected, otherwise a folder picker appears.",
2648
2648
  "If no durable workspace folder is connected for writing canvases, say so and stop."
2649
2649
  ].join(" ") : "Session attachments live under the shared in-memory root and are readable via workspace_read / workspace_list."} Workspace paths use a connected root prefix from workspace_list (never write bare names at the composite root unless a single durable folder can auto-qualify them). For specialized workflows (e.g. canvas.js), call skills.list to discover registered skills, then skills.load with the matching name before following those instructions.`;
@@ -3590,4 +3590,4 @@ function registerSkillCommands() {
3590
3590
  //#endregion
3591
3591
  export { detectEffortCapability as C, AI_VIEW_NAME as D, AI_SETTINGS_KEY as E, OPEN_AI_SETTINGS_COMMAND as O, parseModelIds as S, AI_SETTINGS_EDITOR_ID as T, readPromptAttachmentFromFile as _, listSkillContributions as a, defaultProvidersSettings as b, resolveSkillBody as c, parseSkillMarkdown as d, estimateSessionContextUsage as f, ATTACHMENT_FILE_ACCEPT as g, formatTokenCount as h, SYSTEM_SKILLS as i, TOPIC as k, isSkillContribution as l, formatContextPercent as m, CognitiveRuntime as n, registerSkillMarkdown as o, formatBucketDetail as p, cognitiveRuntime as r, resolveSkill as s, registerSkillCommands as t, formatSkillForPrompt as u, OpenAICompatibleProvider as v, loadModelsCatalog as w, listConfiguredModelIds as x, fetchOpenAICompatibleModels as y };
3592
3592
 
3593
- //# sourceMappingURL=runtime-B0IHjzQO.js.map
3593
+ //# sourceMappingURL=runtime-DVzLyx8h.js.map