@ahggg/dsh-side-chat 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +19 -8
  2. package/README.zh-CN.md +19 -8
  3. package/lib/client/apply.d.ts.map +1 -1
  4. package/lib/client/apply.js +7 -1
  5. package/lib/client/apply.js.map +1 -1
  6. package/lib/client/panel/SelectionQuote.d.ts +6 -4
  7. package/lib/client/panel/SelectionQuote.d.ts.map +1 -1
  8. package/lib/client/panel/SelectionQuote.js +43 -3
  9. package/lib/client/panel/SelectionQuote.js.map +1 -1
  10. package/lib/client/panel/SideChatPanel.d.ts +1 -2
  11. package/lib/client/panel/SideChatPanel.d.ts.map +1 -1
  12. package/lib/client/panel/SideChatPanel.js +2 -2
  13. package/lib/client/panel/SideChatPanel.js.map +1 -1
  14. package/lib/client/panel/StopIcon.d.ts +3 -0
  15. package/lib/client/panel/StopIcon.d.ts.map +1 -0
  16. package/lib/client/panel/StopIcon.js +6 -0
  17. package/lib/client/panel/StopIcon.js.map +1 -0
  18. package/lib/client/panel/messages.d.ts +2 -2
  19. package/lib/client/panel/messages.d.ts.map +1 -1
  20. package/lib/client/panel/messages.js +4 -4
  21. package/lib/client/panel/messages.js.map +1 -1
  22. package/lib/client/parent-composer/ParentConversationAnnotations.d.ts +27 -0
  23. package/lib/client/parent-composer/ParentConversationAnnotations.d.ts.map +1 -0
  24. package/lib/client/parent-composer/ParentConversationAnnotations.js +97 -0
  25. package/lib/client/parent-composer/ParentConversationAnnotations.js.map +1 -0
  26. package/lib/client/parent-composer/add-to-conversation.d.ts +64 -0
  27. package/lib/client/parent-composer/add-to-conversation.d.ts.map +1 -1
  28. package/lib/client/parent-composer/add-to-conversation.js +182 -0
  29. package/lib/client/parent-composer/add-to-conversation.js.map +1 -1
  30. package/lib/client/rc6/ArchivedConversation.d.ts +1 -2
  31. package/lib/client/rc6/ArchivedConversation.d.ts.map +1 -1
  32. package/lib/client/rc6/ArchivedConversation.js +8 -6
  33. package/lib/client/rc6/ArchivedConversation.js.map +1 -1
  34. package/lib/client/rc6/Rc6SideChatOverlay.d.ts.map +1 -1
  35. package/lib/client/rc6/Rc6SideChatOverlay.js +56 -10
  36. package/lib/client/rc6/Rc6SideChatOverlay.js.map +1 -1
  37. package/lib/client/rc6/context.d.ts +6 -1
  38. package/lib/client/rc6/context.d.ts.map +1 -1
  39. package/lib/client/rc6/sessions-adapter.d.ts +6 -0
  40. package/lib/client/rc6/sessions-adapter.d.ts.map +1 -1
  41. package/lib/client/rc6/sessions-adapter.js +30 -0
  42. package/lib/client/rc6/sessions-adapter.js.map +1 -1
  43. package/lib/client/selection/SelectionActions.d.ts +5 -1
  44. package/lib/client/selection/SelectionActions.d.ts.map +1 -1
  45. package/lib/client/selection/SelectionActions.js +69 -7
  46. package/lib/client/selection/SelectionActions.js.map +1 -1
  47. package/lib/client.js +665 -162
  48. package/lib/client.js.map +1 -1
  49. package/package.json +5 -1
package/lib/client.js CHANGED
@@ -6,8 +6,424 @@ window.__ModuleLoader__.load({
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react = require("react");
8
8
  let react_jsx_runtime = require("react/jsx-runtime");
9
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
10
  //#region \0dsh-side-chat-css:L2hvbWUvcnVubmVyL3dvcmsvZHNoLXNpZGUtY2hhdC9kc2gtc2lkZS1jaGF0L3NyYy9jbGllbnQvcGFuZWwvc2lkZS1jaGF0LmNzcw
10
- var _dsh_side_chat_css_L2hvbWUvcnVubmVyL3dvcmsvZHNoLXNpZGUtY2hhdC9kc2gtc2lkZS1jaGF0L3NyYy9jbGllbnQvcGFuZWwvc2lkZS1jaGF0LmNzcw_default = ".dsh-side-chat-overlay {\n pointer-events: none;\n}\n\n.dsh-side-chat-overlay > * {\n pointer-events: auto;\n}\n\n.dsh-side-chat-panel {\n --side-chat-border: var(--dsw-border, #d8d8de);\n --side-chat-bg: var(--dsw-surface, #ffffff);\n --side-chat-muted: var(--dsw-text-muted, #62636a);\n position: fixed;\n z-index: 70;\n right: clamp(12px, 2vw, 20px);\n bottom: clamp(12px, 2vw, 20px);\n display: flex;\n width: min(840px, calc(100vw - 32px));\n height: clamp(460px, 62dvh, 980px);\n max-height: calc(100dvh - 32px);\n min-width: 0;\n min-height: 0;\n box-sizing: border-box;\n flex-direction: column;\n overflow: hidden;\n border: 1px solid var(--side-chat-border);\n border-radius: 28px;\n background: var(--side-chat-bg);\n color: var(--dsw-text, #19191d);\n box-shadow: 0 12px 36px rgb(0 0 0 / 11%), 0 2px 8px rgb(0 0 0 / 6%);\n}\n\n.dsh-side-chat-conversation {\n display: flex;\n height: 100%;\n min-height: 0;\n flex-direction: column;\n overflow: hidden;\n}\n\n.dsh-side-chat-transcript {\n display: flex;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n gap: 12px;\n overflow-x: hidden;\n overflow-y: auto;\n padding: 18px 20px 24px;\n scrollbar-color: color-mix(in srgb, var(--side-chat-muted) 34%, transparent) transparent;\n scrollbar-width: thin;\n}\n\n.dsh-side-chat-message {\n max-width: 92%;\n padding: 10px 12px;\n border: 1px solid var(--side-chat-border);\n border-radius: 12px;\n background: var(--dsw-surface-subtle, #f7f7f9);\n}\n\n.dsh-side-chat-message[data-role=\"user\"] {\n align-self: end;\n background: var(--dsw-accent-soft, #eef4ff);\n}\n\n.dsh-side-chat-message[data-role=\"assistant\"] {\n align-self: start;\n max-width: 100%;\n border-color: transparent;\n background: transparent;\n}\n.dsh-side-chat-message-role,\n.dsh-side-chat-message-note { display: block; margin-bottom: 5px; color: var(--side-chat-muted); font-size: 12px; }\n.dsh-side-chat-message-text { white-space: pre-wrap; overflow-wrap: anywhere; }\n.dsh-side-chat-message pre,\n.dsh-side-chat-turn-notice pre { overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; }\n.dsh-side-chat-turn-notice,\n.dsh-side-chat-interaction,\n.dsh-side-chat-queue { padding: 10px; border: 1px solid var(--side-chat-border); border-radius: 10px; }\n.dsh-side-chat-interaction fieldset { margin: 8px 0; border: 1px solid var(--side-chat-border); border-radius: 8px; }\n.dsh-side-chat-question-option { display: flex; gap: 8px; margin: 8px 0; }\n.dsh-side-chat-interaction textarea { width: 100%; box-sizing: border-box; resize: vertical; }\n.dsh-side-chat-interaction-actions,\n.dsh-side-chat-composer > div,\n.dsh-side-chat-queue > div { display: flex; justify-content: end; gap: 8px; }\n.dsh-side-chat-interaction button,\n.dsh-side-chat-composer button,\n.dsh-side-chat-queue button { min-height: 32px; border: 1px solid var(--side-chat-border); border-radius: 7px; background: var(--dsw-control, #f7f7f9); color: inherit; cursor: pointer; }\n.dsh-side-chat-composer {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 8px;\n align-items: end;\n margin: 0 12px 12px;\n padding: 8px 8px 8px 12px;\n border: 1px solid var(--side-chat-border);\n border-radius: 24px;\n background: var(--side-chat-bg);\n box-shadow: 0 2px 8px rgb(0 0 0 / 5%);\n}\n.dsh-side-chat-composer textarea {\n width: 100%;\n height: auto;\n min-height: 24px;\n max-height: 160px;\n box-sizing: border-box;\n resize: none;\n overflow-y: hidden;\n padding: 6px;\n border: 0;\n outline: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1.5;\n}\n.dsh-side-chat-composer button { align-self: end; }\n.dsh-side-chat-loading { display: grid; height: 100%; place-items: center; color: var(--side-chat-muted); }\n\n.dsh-side-chat-header {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 8px 12px;\n align-items: center;\n flex: 0 0 auto;\n min-height: 46px;\n box-sizing: border-box;\n padding: 5px 10px 5px 16px;\n border-bottom: 1px solid var(--side-chat-border);\n background: var(--side-chat-bg);\n}\n\n.dsh-side-chat-heading { display: flex; min-width: 0; flex-direction: column; }\n.dsh-side-chat-heading strong { font-size: 14px; font-weight: 600; }\n.dsh-side-chat-footer { color: var(--side-chat-muted); font-size: 12px; }\n.dsh-side-chat-header button,\n.dsh-side-chat-inline-actions button,\n.dsh-side-chat-draft button,\n.dsh-side-chat-error button,\n.dsh-side-chat-selection-actions button {\n min-height: 32px;\n border: 1px solid var(--side-chat-border);\n border-radius: 7px;\n background: var(--dsw-control, #f7f7f9);\n color: inherit;\n cursor: pointer;\n}\n.dsh-side-chat-header button:disabled { cursor: not-allowed; opacity: .55; }\n.dsh-side-chat-header .dsh-side-chat-heading {\n align-items: flex-start;\n min-height: 0;\n padding: 4px 0;\n border: 0;\n background: transparent;\n text-align: left;\n}\n.dsh-side-chat-header > button:last-child {\n width: 32px;\n min-height: 32px;\n padding: 0;\n border: 0;\n border-radius: 999px;\n background: transparent;\n font-size: 20px;\n line-height: 1;\n}\n.dsh-side-chat-header > button:last-child:hover { background: var(--dsw-surface-subtle, #f3f3f5); }\n\n.dsh-side-chat-quote { position: relative; max-width: 100%; align-self: flex-start; }\n.dsh-side-chat-quote-chip {\n display: inline-flex;\n min-height: 36px;\n align-items: center;\n overflow: hidden;\n padding: 0;\n border: 1px solid var(--side-chat-border);\n border-radius: 999px;\n background: var(--side-chat-bg);\n transition: background-color 120ms ease;\n}\n.dsh-side-chat-quote:hover .dsh-side-chat-quote-chip,\n.dsh-side-chat-quote:focus-within .dsh-side-chat-quote-chip,\n.dsh-side-chat-quote[data-expanded] .dsh-side-chat-quote-chip { background: var(--dsw-surface-subtle, #f3f3f5); }\n.dsh-side-chat-quote-chip .dsh-side-chat-quote-trigger {\n display: inline-flex;\n min-height: 34px;\n align-items: center;\n gap: 8px;\n padding: 0 11px;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n.dsh-side-chat-quote-trigger strong { font-size: 13px; font-weight: 500; line-height: 1; }\n.dsh-side-chat-quote-icon {\n width: 16px;\n height: 16px;\n flex: 0 0 auto;\n color: var(--side-chat-muted);\n fill: none;\n stroke: currentColor;\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-width: 1.7;\n}\n.dsh-side-chat-quote-chip .dsh-side-chat-quote-remove {\n display: grid;\n width: 0;\n height: 34px;\n min-height: 34px;\n box-sizing: border-box;\n flex: 0 0 auto;\n place-items: center;\n overflow: hidden;\n padding: 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: var(--side-chat-muted);\n cursor: pointer;\n font: inherit;\n font-size: 18px;\n line-height: 1;\n opacity: 0;\n pointer-events: none;\n transition: width 120ms ease, margin-left 120ms ease, opacity 100ms ease, background-color 100ms ease;\n}\n.dsh-side-chat-quote:hover .dsh-side-chat-quote-remove,\n.dsh-side-chat-quote:focus-within .dsh-side-chat-quote-remove {\n width: 30px;\n opacity: 1;\n pointer-events: auto;\n}\n.dsh-side-chat-quote-remove:hover { background: rgb(0 0 0 / 6%); color: inherit; }\n.dsh-side-chat-quote-details {\n position: absolute;\n z-index: 10;\n bottom: calc(100% + 8px);\n left: 0;\n width: min(520px, calc(100vw - 64px));\n max-width: calc(100vw - 48px);\n box-sizing: border-box;\n padding: 14px 16px;\n border: 1px solid var(--side-chat-border);\n border-radius: 16px;\n background: var(--side-chat-bg);\n box-shadow: 0 4px 14px rgb(0 0 0 / 8%);\n opacity: 0;\n pointer-events: none;\n transform: translateY(4px);\n visibility: hidden;\n transition: opacity 100ms ease, transform 120ms ease, visibility 100ms ease;\n}\n.dsh-side-chat-quote:hover .dsh-side-chat-quote-details,\n.dsh-side-chat-quote:focus-within .dsh-side-chat-quote-details,\n.dsh-side-chat-quote[data-expanded] .dsh-side-chat-quote-details {\n opacity: 1;\n transform: translateY(0);\n visibility: visible;\n}\n.dsh-side-chat-quote[data-expanded] .dsh-side-chat-quote-details { pointer-events: auto; }\n.dsh-side-chat-annotated-user-message .dsh-side-chat-quote-details {\n top: calc(100% + 8px);\n right: 0;\n bottom: auto;\n left: auto;\n}\n.dsh-side-chat-quote-details-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; }\n.dsh-side-chat-quote-details-header strong { color: var(--side-chat-muted); font-size: 13px; font-weight: 500; }\n.dsh-side-chat-quote-details-header button {\n min-height: 28px;\n padding-inline: 10px;\n border: 1px solid var(--side-chat-border);\n border-radius: 999px;\n background: var(--side-chat-bg);\n color: inherit;\n cursor: pointer;\n}\n.dsh-side-chat-quote pre { max-height: 180px; margin: 8px 0 0; overflow: auto; white-space: pre-wrap; font: inherit; }\n.dsh-side-chat-error { margin: 10px 16px 0; padding: 10px 12px; border: 1px solid var(--side-chat-border); border-radius: 14px; background: var(--dsw-surface-subtle, #f7f7f9); }\n.dsh-side-chat-error { border-color: var(--dsw-danger, #b42318); }\n.dsh-side-chat-body { min-height: 0; flex: 1; overflow: hidden; }\n.dsh-side-chat-annotated-user-message {\n display: flex;\n max-width: 92%;\n align-self: end;\n align-items: flex-start;\n flex-direction: column;\n gap: 8px;\n}\n.dsh-side-chat-annotated-user-message .dsh-side-chat-message { max-width: 100%; align-self: stretch; }\n.dsh-side-chat-draft {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n min-height: 0;\n flex: 0 0 auto;\n gap: 8px;\n align-items: end;\n margin: auto 12px 12px;\n padding: 12px;\n border: 1px solid var(--side-chat-border);\n border-radius: 24px;\n background: var(--side-chat-bg);\n box-shadow: 0 2px 8px rgb(0 0 0 / 5%);\n}\n.dsh-side-chat-draft > .dsh-side-chat-quote { grid-column: 1 / -1; }\n.dsh-side-chat-draft label {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n}\n.dsh-side-chat-draft textarea {\n width: 100%;\n height: auto;\n min-height: 24px;\n max-height: 160px;\n box-sizing: border-box;\n resize: none;\n overflow-y: hidden;\n padding: 6px 2px;\n border: 0;\n outline: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1.5;\n}\n.dsh-side-chat-draft > button { align-self: end; }\n.dsh-side-chat-panel .dsh-side-chat-send-button {\n display: grid;\n width: 34px;\n height: 34px;\n min-height: 34px;\n flex: none;\n place-items: center;\n padding: 1px 6px;\n border: 0;\n border-radius: 999px;\n background: var(--dsw-alias-button-info-fill, #4176e6);\n color: #fff;\n cursor: pointer;\n line-height: 1;\n transform: translateY(-2px);\n transition: background-color 100ms ease;\n}\n.dsh-side-chat-panel .dsh-side-chat-send-button:hover:not(:disabled) {\n background: var(--dsw-alias-button-info-hover, #3467d6);\n}\n.dsh-side-chat-panel .dsh-side-chat-send-button:disabled { cursor: default; opacity: .4; }\n.dsh-side-chat-footer { display: none; }\n.dsh-side-chat-announcer { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }\n\n.dsh-side-chat-selection-actions {\n position: fixed;\n z-index: 90;\n display: flex;\n max-width: calc(100vw - 16px);\n flex-wrap: wrap;\n gap: 0;\n padding: 0;\n border: 1px solid var(--dsw-border, #d8d8de);\n border-radius: 999px;\n background: var(--dsw-surface, #fff);\n box-shadow: 0 4px 14px rgb(0 0 0 / 12%);\n overflow: hidden;\n transition: background-color 120ms ease;\n}\n.dsh-side-chat-selection-actions:hover,\n.dsh-side-chat-selection-actions:focus-within { background: var(--dsw-surface-subtle, #f3f3f5); }\n.dsh-side-chat-selection-actions button {\n min-height: 36px;\n padding: 0 14px;\n border: 0;\n border-radius: inherit;\n background: transparent;\n color: inherit;\n}\n\n@media (max-width: 900px) {\n .dsh-side-chat-panel {\n right: 12px;\n bottom: 12px;\n width: calc(100vw - 24px);\n max-height: calc(100dvh - 24px);\n border-radius: 24px;\n }\n}\n\n@media (max-width: 720px) {\n .dsh-side-chat-panel {\n right: 8px;\n bottom: 8px;\n width: calc(100vw - 16px);\n height: min(78dvh, 760px);\n max-height: calc(100dvh - 16px);\n border-radius: 22px;\n }\n .dsh-side-chat-transcript { padding: 14px 14px 20px; }\n .dsh-side-chat-header { padding-left: 14px; }\n .dsh-side-chat-error { margin-inline: 12px; }\n}\n\n@media (max-height: 620px) {\n .dsh-side-chat-panel {\n bottom: 8px;\n height: calc(100dvh - 16px);\n max-height: calc(100dvh - 16px);\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .dsh-side-chat-panel { animation: dsh-side-chat-enter 160ms ease-out; }\n @keyframes dsh-side-chat-enter { from { transform: translateY(18px) scale(.985); opacity: .7; } }\n}\n\n@media (forced-colors: active) {\n .dsh-side-chat-panel,\n .dsh-side-chat-selection-actions { border: 1px solid CanvasText; }\n}\n";
11
+ var _dsh_side_chat_css_L2hvbWUvcnVubmVyL3dvcmsvZHNoLXNpZGUtY2hhdC9kc2gtc2lkZS1jaGF0L3NyYy9jbGllbnQvcGFuZWwvc2lkZS1jaGF0LmNzcw_default = ".dsh-side-chat-overlay {\n pointer-events: none;\n}\n\n.dsh-side-chat-overlay > * {\n pointer-events: auto;\n}\n\n.dsh-side-chat-panel {\n --side-chat-border: var(--dsw-border, #d8d8de);\n --side-chat-bg: var(--dsw-surface, #ffffff);\n --side-chat-muted: var(--dsw-text-muted, #62636a);\n position: fixed;\n z-index: 70;\n right: clamp(12px, 2vw, 20px);\n bottom: clamp(12px, 2vw, 20px);\n display: flex;\n width: min(840px, calc(100vw - 32px));\n height: clamp(460px, 62dvh, 980px);\n max-height: calc(100dvh - 32px);\n min-width: 0;\n min-height: 0;\n box-sizing: border-box;\n flex-direction: column;\n overflow: hidden;\n border: 1px solid var(--side-chat-border);\n border-radius: 28px;\n background: var(--side-chat-bg);\n color: var(--dsw-text, #19191d);\n box-shadow: 0 12px 36px rgb(0 0 0 / 11%), 0 2px 8px rgb(0 0 0 / 6%);\n}\n\n.dsh-side-chat-conversation {\n display: flex;\n height: 100%;\n min-height: 0;\n flex-direction: column;\n overflow: hidden;\n}\n\n.dsh-side-chat-transcript {\n display: flex;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n gap: 12px;\n overflow-x: hidden;\n overflow-y: auto;\n padding: 18px 20px 24px;\n scrollbar-color: color-mix(in srgb, var(--side-chat-muted) 34%, transparent) transparent;\n scrollbar-width: thin;\n}\n\n.dsh-side-chat-message {\n max-width: 92%;\n padding: 10px 12px;\n border: 1px solid var(--side-chat-border);\n border-radius: 12px;\n background: var(--dsw-surface-subtle, #f7f7f9);\n}\n\n.dsh-side-chat-message[data-role=\"user\"] {\n align-self: end;\n background: var(--dsw-accent-soft, #eef4ff);\n}\n\n.dsh-side-chat-message[data-role=\"assistant\"] {\n align-self: start;\n max-width: 100%;\n border-color: transparent;\n background: transparent;\n}\n.dsh-side-chat-message-role,\n.dsh-side-chat-message-note { display: block; margin-bottom: 5px; color: var(--side-chat-muted); font-size: 12px; }\n.dsh-side-chat-message-text { white-space: pre-wrap; overflow-wrap: anywhere; }\n.dsh-side-chat-message pre,\n.dsh-side-chat-turn-notice pre { overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; }\n.dsh-side-chat-turn-notice,\n.dsh-side-chat-interaction,\n.dsh-side-chat-queue { padding: 10px; border: 1px solid var(--side-chat-border); border-radius: 10px; }\n.dsh-side-chat-interaction fieldset { margin: 8px 0; border: 1px solid var(--side-chat-border); border-radius: 8px; }\n.dsh-side-chat-question-option { display: flex; gap: 8px; margin: 8px 0; }\n.dsh-side-chat-interaction textarea { width: 100%; box-sizing: border-box; resize: vertical; }\n.dsh-side-chat-interaction-actions,\n.dsh-side-chat-composer > div,\n.dsh-side-chat-queue > div { display: flex; justify-content: end; gap: 8px; }\n.dsh-side-chat-interaction button,\n.dsh-side-chat-composer button,\n.dsh-side-chat-queue button { min-height: 32px; border: 1px solid var(--side-chat-border); border-radius: 7px; background: var(--dsw-control, #f7f7f9); color: inherit; cursor: pointer; }\n.dsh-side-chat-composer {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 8px;\n align-items: end;\n margin: 0 12px 12px;\n padding: 8px 8px 8px 12px;\n border: 1px solid var(--side-chat-border);\n border-radius: 24px;\n background: var(--side-chat-bg);\n box-shadow: 0 2px 8px rgb(0 0 0 / 5%);\n}\n.dsh-side-chat-composer textarea {\n width: 100%;\n height: auto;\n min-height: 24px;\n max-height: 160px;\n box-sizing: border-box;\n resize: none;\n overflow-y: hidden;\n padding: 6px;\n border: 0;\n outline: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1.5;\n}\n.dsh-side-chat-composer button { align-self: end; }\n.dsh-side-chat-loading { display: grid; height: 100%; place-items: center; color: var(--side-chat-muted); }\n\n.dsh-side-chat-header {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 8px 12px;\n align-items: center;\n flex: 0 0 auto;\n min-height: 46px;\n box-sizing: border-box;\n padding: 5px 10px 5px 16px;\n border-bottom: 1px solid var(--side-chat-border);\n background: var(--side-chat-bg);\n}\n\n.dsh-side-chat-heading { display: flex; min-width: 0; flex-direction: column; }\n.dsh-side-chat-heading strong { font-size: 14px; font-weight: 600; }\n.dsh-side-chat-footer { color: var(--side-chat-muted); font-size: 12px; }\n.dsh-side-chat-header button,\n.dsh-side-chat-inline-actions button,\n.dsh-side-chat-draft button,\n.dsh-side-chat-error button,\n.dsh-side-chat-selection-actions button {\n min-height: 32px;\n border: 1px solid var(--side-chat-border);\n border-radius: 7px;\n background: var(--dsw-control, #f7f7f9);\n color: inherit;\n cursor: pointer;\n}\n.dsh-side-chat-header button:disabled { cursor: not-allowed; opacity: .55; }\n.dsh-side-chat-header .dsh-side-chat-heading {\n align-items: flex-start;\n min-height: 0;\n padding: 4px 0;\n border: 0;\n background: transparent;\n text-align: left;\n}\n.dsh-side-chat-header > button:last-child {\n width: 32px;\n min-height: 32px;\n padding: 0;\n border: 0;\n border-radius: 999px;\n background: transparent;\n font-size: 20px;\n line-height: 1;\n}\n.dsh-side-chat-header > button:last-child:hover { background: var(--dsw-surface-subtle, #f3f3f5); }\n\n.dsh-side-chat-quote { position: relative; max-width: 100%; align-self: flex-start; }\n.dsh-side-chat-quote-chip {\n display: inline-flex;\n min-height: 36px;\n align-items: center;\n overflow: hidden;\n padding: 0;\n border: 1px solid var(--side-chat-border);\n border-radius: 999px;\n background: var(--side-chat-bg);\n transition: background-color 120ms ease;\n}\n.dsh-side-chat-quote:hover .dsh-side-chat-quote-chip,\n.dsh-side-chat-quote:focus-within .dsh-side-chat-quote-chip,\n.dsh-side-chat-quote[data-expanded] .dsh-side-chat-quote-chip { background: var(--dsw-surface-subtle, #f3f3f5); }\n.dsh-side-chat-quote-chip .dsh-side-chat-quote-trigger {\n display: inline-flex;\n min-height: 34px;\n align-items: center;\n gap: 8px;\n padding: 0 11px;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n.dsh-side-chat-quote-trigger strong { font-size: 13px; font-weight: 500; line-height: 1; }\n.dsh-side-chat-quote-icon {\n width: 16px;\n height: 16px;\n flex: 0 0 auto;\n color: var(--side-chat-muted);\n fill: none;\n stroke: currentColor;\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-width: 1.7;\n}\n.dsh-side-chat-quote-chip .dsh-side-chat-quote-remove {\n display: grid;\n width: 0;\n height: 34px;\n min-height: 34px;\n box-sizing: border-box;\n flex: 0 0 auto;\n place-items: center;\n overflow: hidden;\n padding: 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: var(--side-chat-muted);\n cursor: pointer;\n font: inherit;\n font-size: 18px;\n line-height: 1;\n opacity: 0;\n pointer-events: none;\n transition: width 120ms ease, margin-left 120ms ease, opacity 100ms ease, background-color 100ms ease;\n}\n.dsh-side-chat-quote:hover .dsh-side-chat-quote-remove,\n.dsh-side-chat-quote:focus-within .dsh-side-chat-quote-remove {\n width: 30px;\n opacity: 1;\n pointer-events: auto;\n}\n.dsh-side-chat-quote-remove:hover { background: rgb(0 0 0 / 6%); color: inherit; }\n.dsh-side-chat-quote-details {\n position: absolute;\n z-index: 10;\n bottom: calc(100% + 8px);\n left: 0;\n width: min(520px, calc(100vw - 64px));\n max-width: calc(100vw - 48px);\n box-sizing: border-box;\n padding: 14px 16px;\n border: 1px solid var(--side-chat-border);\n border-radius: 16px;\n background: var(--side-chat-bg);\n box-shadow: 0 4px 14px rgb(0 0 0 / 8%);\n font-size: 14px;\n line-height: 1.45;\n opacity: 0;\n pointer-events: none;\n transform: translate(var(--dsh-side-chat-quote-offset-x, 0px), 4px);\n visibility: hidden;\n transition: opacity 100ms ease, transform 120ms ease, visibility 100ms ease;\n}\n.dsh-side-chat-quote-details::before {\n content: '';\n position: absolute;\n right: 0;\n bottom: -8px;\n left: 0;\n height: 8px;\n}\n.dsh-side-chat-quote:hover .dsh-side-chat-quote-details,\n.dsh-side-chat-quote[data-hovered] .dsh-side-chat-quote-details,\n.dsh-side-chat-quote:focus-within .dsh-side-chat-quote-details,\n.dsh-side-chat-quote[data-expanded] .dsh-side-chat-quote-details {\n opacity: 1;\n pointer-events: auto;\n transform: translate(var(--dsh-side-chat-quote-offset-x, 0px), 0);\n visibility: visible;\n}\n.dsh-side-chat-annotated-user-message .dsh-side-chat-quote-details {\n top: calc(100% + 8px);\n right: 0;\n bottom: auto;\n left: auto;\n}\n.dsh-side-chat-annotated-user-message .dsh-side-chat-quote-details::before {\n top: -8px;\n bottom: auto;\n}\n.dsh-side-chat-quote-details-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; }\n.dsh-side-chat-quote-details-header strong { color: var(--side-chat-muted); font-size: 13px; font-weight: 500; }\n.dsh-side-chat-quote-detail + .dsh-side-chat-quote-detail {\n margin-top: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--side-chat-border);\n}\n.dsh-side-chat-quote pre {\n max-height: 180px;\n margin: 4px 0 0;\n overflow: auto;\n white-space: pre-wrap;\n font: inherit;\n}\n.dsh-side-chat-quote-comment {\n margin-top: 9px;\n}\n.dsh-side-chat-quote-comment > strong { color: var(--side-chat-muted); font-size: 13px; font-weight: 500; }\n.dsh-side-chat-quote-comment > pre { margin-top: 4px; }\n.dsh-side-chat-error { margin: 10px 16px 0; padding: 10px 12px; border: 1px solid var(--side-chat-border); border-radius: 14px; background: var(--dsw-surface-subtle, #f7f7f9); }\n.dsh-side-chat-error { border-color: var(--dsw-danger, #b42318); }\n.dsh-side-chat-body { min-height: 0; flex: 1; overflow: hidden; }\n.dsh-side-chat-annotated-user-message {\n display: flex;\n max-width: 92%;\n align-self: end;\n align-items: flex-start;\n flex-direction: column;\n gap: 8px;\n}\n.dsh-side-chat-annotated-user-message .dsh-side-chat-message { max-width: 100%; align-self: stretch; }\n\n/* The DSH occurrence remains the durable serialization carrier, while this\n plugin-owned capsule supplies the visible and interactive projection. */\n[data-composer-seat] [data-decoration=\"chip\"][title=\"__dsh_side_chat_annotations__\"] {\n visibility: hidden;\n}\n.dsh-side-chat-parent-annotation-dock,\n.dsh-side-chat-parent-user-message {\n --side-chat-border: var(--dsw-border, #d8d8de);\n --side-chat-bg: var(--dsw-surface, #ffffff);\n --side-chat-muted: var(--dsw-text-muted, #62636a);\n color: var(--dsw-text, #19191d);\n}\n.dsh-side-chat-parent-annotation-dock {\n position: relative;\n z-index: 20;\n width: calc(100% - 32px);\n max-width: var(--dsh-composer-card-max-width, 780px);\n height: 0;\n margin: 0 auto;\n pointer-events: none;\n}\n.dsh-side-chat-parent-annotation-dock > .dsh-side-chat-quote {\n position: absolute;\n top: 16px;\n left: 16px;\n pointer-events: auto;\n}\n.dsh-side-chat-parent-user-message {\n display: flex;\n width: 100%;\n flex-direction: column;\n align-items: flex-end;\n gap: 8px;\n}\n.dsh-side-chat-parent-user-message > .dsh-side-chat-quote { align-self: flex-end; }\n.dsh-side-chat-parent-user-message > .dsh-side-chat-quote .dsh-side-chat-quote-details {\n right: 0;\n left: auto;\n}\n.dsh-side-chat-draft {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n min-height: 0;\n flex: 0 0 auto;\n gap: 8px;\n align-items: end;\n margin: auto 12px 12px;\n padding: 12px;\n border: 1px solid var(--side-chat-border);\n border-radius: 24px;\n background: var(--side-chat-bg);\n box-shadow: 0 2px 8px rgb(0 0 0 / 5%);\n}\n.dsh-side-chat-draft > .dsh-side-chat-quote { grid-column: 1 / -1; }\n.dsh-side-chat-draft label {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n}\n.dsh-side-chat-draft textarea {\n width: 100%;\n height: auto;\n min-height: 24px;\n max-height: 160px;\n box-sizing: border-box;\n resize: none;\n overflow-y: hidden;\n padding: 6px 2px;\n border: 0;\n outline: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1.5;\n}\n.dsh-side-chat-draft > button { align-self: end; }\n.dsh-side-chat-panel .dsh-side-chat-send-button,\n.dsh-side-chat-panel .dsh-side-chat-stop-button {\n display: grid;\n width: 34px;\n height: 34px;\n min-height: 34px;\n flex: none;\n place-items: center;\n padding: 1px 6px;\n border: 0;\n border-radius: 999px;\n background: var(--dsw-alias-button-info-fill, #4176e6);\n color: #fff;\n cursor: pointer;\n line-height: 1;\n transform: translateY(-2px);\n transition: background-color 100ms ease;\n}\n.dsh-side-chat-panel .dsh-side-chat-send-button:hover:not(:disabled),\n.dsh-side-chat-panel .dsh-side-chat-stop-button:hover:not(:disabled) {\n background: var(--dsw-alias-button-info-hover, #3467d6);\n}\n.dsh-side-chat-panel .dsh-side-chat-send-button:disabled,\n.dsh-side-chat-panel .dsh-side-chat-stop-button:disabled { cursor: default; opacity: .4; }\n.dsh-side-chat-footer { display: none; }\n.dsh-side-chat-announcer { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }\n\n.dsh-side-chat-selection-actions {\n position: fixed;\n z-index: 90;\n display: flex;\n max-width: calc(100vw - 16px);\n flex-wrap: wrap;\n gap: 0;\n padding: 0;\n border: 1px solid var(--dsw-border, #d8d8de);\n border-radius: 999px;\n background: var(--dsw-surface, #fff);\n box-shadow: 0 4px 14px rgb(0 0 0 / 12%);\n overflow: hidden;\n}\n.dsh-side-chat-selection-actions button {\n min-height: 36px;\n padding: 0 14px;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: inherit;\n transition: background-color 120ms ease;\n}\n.dsh-side-chat-selection-actions button:hover:not(:disabled),\n.dsh-side-chat-selection-actions button:focus-visible {\n background: var(--dsw-surface-subtle, #f3f3f5);\n}\n.dsh-side-chat-selection-actions button + button {\n border-left: 1px solid var(--dsw-border, #d8d8de);\n border-radius: 0;\n}\n\n.dsh-side-chat-selection-marker {\n position: fixed;\n z-index: 91;\n display: grid;\n width: 28px;\n height: 28px;\n place-items: center;\n border: 2px solid var(--dsw-surface, #fff);\n border-radius: 999px;\n background: var(--dsw-alias-button-info, #1473e6);\n box-shadow: 0 2px 6px rgb(0 0 0 / 12%);\n color: #fff;\n font-size: 13px;\n font-weight: 600;\n line-height: 1;\n pointer-events: none;\n}\n\n.dsh-side-chat-selection-comment {\n position: fixed;\n z-index: 92;\n display: grid;\n max-width: calc(100vw - 16px);\n box-sizing: border-box;\n gap: 10px;\n padding: 12px;\n border: 1px solid var(--dsw-border, #d8d8de);\n border-radius: 20px;\n background: var(--dsw-surface, #fff);\n box-shadow: 0 5px 18px rgb(0 0 0 / 9%);\n color: var(--dsw-text, #19191d);\n}\n.dsh-side-chat-selection-comment textarea {\n width: 100%;\n min-height: 48px;\n max-height: 128px;\n box-sizing: border-box;\n resize: none;\n padding: 6px 8px;\n overflow-y: auto;\n border: 0;\n outline: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1.45;\n}\n.dsh-side-chat-selection-comment-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n}\n.dsh-side-chat-selection-comment-actions button {\n min-height: 32px;\n padding: 0 14px;\n border: 1px solid var(--dsw-border, #d8d8de);\n border-radius: 999px;\n background: var(--dsw-surface, #fff);\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n.dsh-side-chat-selection-comment-actions button:hover { background: var(--dsw-surface-subtle, #f3f3f5); }\n.dsh-side-chat-selection-comment-actions .dsh-side-chat-selection-comment-save {\n border-color: transparent;\n background: var(--dsw-alias-button-info, #1473e6);\n color: #fff;\n}\n.dsh-side-chat-selection-comment-actions .dsh-side-chat-selection-comment-save:hover {\n background: var(--dsw-alias-button-info-hover, #3467d6);\n}\n\n@media (max-width: 900px) {\n .dsh-side-chat-panel {\n right: 12px;\n bottom: 12px;\n width: calc(100vw - 24px);\n max-height: calc(100dvh - 24px);\n border-radius: 24px;\n }\n}\n\n@media (max-width: 720px) {\n .dsh-side-chat-panel {\n right: 8px;\n bottom: 8px;\n width: calc(100vw - 16px);\n height: min(78dvh, 760px);\n max-height: calc(100dvh - 16px);\n border-radius: 22px;\n }\n .dsh-side-chat-transcript { padding: 14px 14px 20px; }\n .dsh-side-chat-header { padding-left: 14px; }\n .dsh-side-chat-error { margin-inline: 12px; }\n}\n\n@media (max-height: 620px) {\n .dsh-side-chat-panel {\n bottom: 8px;\n height: calc(100dvh - 16px);\n max-height: calc(100dvh - 16px);\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .dsh-side-chat-panel { animation: dsh-side-chat-enter 160ms ease-out; }\n @keyframes dsh-side-chat-enter { from { transform: translateY(18px) scale(.985); opacity: .7; } }\n}\n\n@media (forced-colors: active) {\n.dsh-side-chat-panel,\n.dsh-side-chat-selection-actions,\n.dsh-side-chat-selection-comment { border: 1px solid CanvasText; }\n}\n";
12
+ //#endregion
13
+ //#region src/client/parent-composer/add-to-conversation.ts
14
+ const SELECTION_REFERENCE_SOURCE = "dsh-side-chat-selection";
15
+ const OBJECT_REPLACEMENT_CHARACTER = "";
16
+ function escapeXmlText(value) {
17
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
18
+ }
19
+ function annotationFromSelection(selection, comment) {
20
+ const trimmedComment = comment?.trim();
21
+ return {
22
+ text: selection.text,
23
+ ...trimmedComment === void 0 || trimmedComment.length === 0 ? {} : { comment: trimmedComment }
24
+ };
25
+ }
26
+ function encodeSelectionReference(annotations) {
27
+ return JSON.stringify({
28
+ version: 1,
29
+ annotations
30
+ });
31
+ }
32
+ function isAnnotation(value) {
33
+ if (typeof value !== "object" || value === null) return false;
34
+ const annotation = value;
35
+ return typeof annotation.text === "string" && (annotation.comment === void 0 || typeof annotation.comment === "string");
36
+ }
37
+ function decodeSelectionReference(ref) {
38
+ const value = JSON.parse(ref);
39
+ if (isAnnotation(value)) return [value];
40
+ if (value.version !== 1 || !Array.isArray(value.annotations) || value.annotations.length === 0 || !value.annotations.every(isAnnotation)) throw new Error("The selected conversation annotation is no longer valid.");
41
+ return value.annotations;
42
+ }
43
+ function selectedContext(annotations) {
44
+ return [
45
+ "<selected_context>",
46
+ ...annotations.flatMap((annotation, index) => annotation.comment === void 0 ? [
47
+ `<annotation index="${String(index + 1)}">`,
48
+ escapeXmlText(annotation.text),
49
+ "</annotation>"
50
+ ] : [
51
+ `<annotation index="${String(index + 1)}">`,
52
+ "<selected_text>",
53
+ escapeXmlText(annotation.text),
54
+ "</selected_text>",
55
+ "<user_comment>",
56
+ escapeXmlText(annotation.comment),
57
+ "</user_comment>",
58
+ "</annotation>"
59
+ ]),
60
+ "</selected_context>"
61
+ ].join("\n");
62
+ }
63
+ function selectionOccurrences(snapshot) {
64
+ return snapshot.occurrences.filter((occurrence) => occurrence.source === SELECTION_REFERENCE_SOURCE);
65
+ }
66
+ /** Read all plugin annotations represented by the current DSH input occurrence. */
67
+ function conversationAnnotations(snapshot) {
68
+ return selectionOccurrences(snapshot).flatMap((occurrence) => {
69
+ try {
70
+ return [...decodeSelectionReference(occurrence.ref)];
71
+ } catch {
72
+ return [];
73
+ }
74
+ });
75
+ }
76
+ function draftWithoutSelectionOccurrences(snapshot) {
77
+ const occurrences = [...selectionOccurrences(snapshot)].sort((a, b) => b.offset - a.offset);
78
+ let draft = snapshot.draft;
79
+ for (const occurrence of occurrences) draft = draft.slice(0, occurrence.offset) + draft.slice(occurrence.offset + 1);
80
+ if (occurrences.some((occurrence) => occurrence.offset === 0)) {
81
+ if (draft.startsWith("\n\n")) draft = draft.slice(2);
82
+ else if (draft.startsWith("\n")) draft = draft.slice(1);
83
+ }
84
+ return draft;
85
+ }
86
+ /** Remove every unsent plugin annotation while preserving the user's draft. */
87
+ function removeConversationAnnotations(input) {
88
+ const snapshot = input.state.getSnapshot();
89
+ if (selectionOccurrences(snapshot).length === 0) return false;
90
+ input.setDraft(draftWithoutSelectionOccurrences(snapshot));
91
+ return true;
92
+ }
93
+ /** Reference codec used by DSH's native composer chip and submit pipeline. */
94
+ const selectionReferenceSource = {
95
+ trigger: "@",
96
+ name: SELECTION_REFERENCE_SOURCE,
97
+ order: 1e3,
98
+ candidates: async () => [],
99
+ onPick: () => void 0,
100
+ codec: {
101
+ clipboardText: (ref) => decodeSelectionReference(ref).map((annotation) => annotation.text).join("\n\n"),
102
+ serialize: async (ref, signal) => {
103
+ if (signal.aborted) throw signal.reason;
104
+ return selectedContext(decodeSelectionReference(ref));
105
+ }
106
+ }
107
+ };
108
+ /** Add one passage to the parent composer's aggregated annotation occurrence. */
109
+ function addSelectionToConversation(input, selection, comment) {
110
+ const before = input.state.getSnapshot();
111
+ const annotations = [...conversationAnnotations(before), annotationFromSelection(selection, comment)];
112
+ const draft = draftWithoutSelectionOccurrences(before);
113
+ if (selectionOccurrences(before).length > 0) input.setDraft(draft);
114
+ const insertionState = input.state.getSnapshot();
115
+ if (!input.insertReference({
116
+ source: SELECTION_REFERENCE_SOURCE,
117
+ ref: encodeSelectionReference(annotations),
118
+ label: "__dsh_side_chat_annotations__",
119
+ clipboardText: annotations.map((annotation) => annotation.text).join("\n\n")
120
+ }, {
121
+ start: 0,
122
+ end: 0,
123
+ draftRev: insertionState.draftRev
124
+ })) return false;
125
+ input.setDraft(`${OBJECT_REPLACEMENT_CHARACTER}\n\n${draft}`);
126
+ return true;
127
+ }
128
+ function unescapeXmlText(value) {
129
+ return value.replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&amp;", "&");
130
+ }
131
+ function parseAnnotationBody(body) {
132
+ const selectedText = /^<selected_text>\n([\s\S]*?)\n<\/selected_text>(?:\n<user_comment>\n([\s\S]*?)\n<\/user_comment>)?$/u.exec(body);
133
+ if (selectedText === null) return { text: unescapeXmlText(body) };
134
+ const comment = selectedText[2];
135
+ return {
136
+ text: unescapeXmlText(selectedText[1] ?? ""),
137
+ ...comment === void 0 ? {} : { comment: unescapeXmlText(comment) }
138
+ };
139
+ }
140
+ /** Parse the durable model form back into the user-facing annotation capsule. */
141
+ function parseAnnotatedConversationPrompt(text) {
142
+ const current = /^<selected_context>\n([\s\S]*?)\n<\/selected_context>\s*/u.exec(text);
143
+ if (current !== null) {
144
+ const annotations = [];
145
+ for (const match of current[1]?.matchAll(/<annotation(?: index="\d+")?>\n([\s\S]*?)\n<\/annotation>/gu) ?? []) annotations.push(parseAnnotationBody(match[1] ?? ""));
146
+ if (annotations.length > 0) return {
147
+ annotations,
148
+ message: text.slice(current[0].length).trim()
149
+ };
150
+ }
151
+ const legacyXml = /^<selected_context source="current-conversation" event-seq="(\d+)">\n?([\s\S]*?)\n?<\/selected_context>\s*/u.exec(text);
152
+ if (legacyXml !== null) return {
153
+ annotations: [{ text: unescapeXmlText(legacyXml[2] ?? "") }],
154
+ message: text.slice(legacyXml[0].length).trim()
155
+ };
156
+ const legacyText = /^Selected passage from the current conversation \(message (\d+)\):\n([\s\S]*?)\nEnd selected passage\.\s*/u.exec(text);
157
+ if (legacyText === null) return void 0;
158
+ return {
159
+ annotations: [{ text: legacyText[2] ?? "" }],
160
+ message: text.slice(legacyText[0].length).trim()
161
+ };
162
+ }
163
+ /** Add the selected quote to the first child prompt. */
164
+ function buildSideChatPrompt(selection, question) {
165
+ const trimmed = question.trim();
166
+ if (selection === void 0) return [{
167
+ type: "text",
168
+ text: trimmed
169
+ }];
170
+ return [{
171
+ type: "text",
172
+ text: [
173
+ `<selected_context source="current-conversation" event-seq="${selection.atSeq}">`,
174
+ escapeXmlText(selection.text),
175
+ "</selected_context>",
176
+ "",
177
+ "<user_question>",
178
+ escapeXmlText(trimmed),
179
+ "</user_question>"
180
+ ].join("\n")
181
+ }];
182
+ }
183
+ //#endregion
184
+ //#region src/client/panel/messages.ts
185
+ const SIDE_CHAT_MESSAGES = Object.freeze({
186
+ en: Object.freeze({
187
+ title: "Side Chat",
188
+ close: "Close Side Chat",
189
+ placeholder: "Ask about this in a Side Chat",
190
+ send: "Send",
191
+ selectedPassage: "Selected passage",
192
+ selectionAttachments: (count) => `${String(count)} ${count === 1 ? "annotation" : "annotations"}`,
193
+ selectionPreviewLabel: "Selected text",
194
+ selectionCommentLabel: "User comment",
195
+ removeSelection: "Remove annotation",
196
+ expand: "Expand",
197
+ collapse: "Collapse",
198
+ temporary: "Archived when closed; history remains on disk",
199
+ referenceOnly: "Inherits the complete parent conversation prefix",
200
+ cannotReopen: "No reopen action",
201
+ sharedWorkspace: "Shares the parent workspace",
202
+ retry: "Retry",
203
+ genericError: "Side Chat error",
204
+ closeError: "Could not close the Side Chat"
205
+ }),
206
+ "zh-CN": Object.freeze({
207
+ title: "侧边对话",
208
+ close: "关闭侧边对话",
209
+ placeholder: "在侧边对话中询问这段内容",
210
+ send: "发送",
211
+ selectedPassage: "所选段落",
212
+ selectionAttachments: (count) => `${String(count)} 条引用`,
213
+ selectionPreviewLabel: "所选文本",
214
+ selectionCommentLabel: "用户批注",
215
+ removeSelection: "移除引用",
216
+ expand: "展开",
217
+ collapse: "收起",
218
+ temporary: "关闭时归档;历史仍保存在磁盘上",
219
+ referenceOnly: "完整继承父会话对话前缀",
220
+ cannotReopen: "不提供重新打开操作",
221
+ sharedWorkspace: "与父会话共享工作区",
222
+ retry: "重试",
223
+ genericError: "侧边对话错误",
224
+ closeError: "无法关闭侧边对话"
225
+ })
226
+ });
227
+ //#endregion
228
+ //#region src/client/panel/SelectionQuote.tsx
229
+ /** Selected passage displayed separately from the user's first question. */
230
+ function SelectionQuote({ selections, messages, onRemove }) {
231
+ const [expanded, setExpanded] = (0, react.useState)(false);
232
+ const [hovered, setHovered] = (0, react.useState)(false);
233
+ const quoteRef = (0, react.useRef)(null);
234
+ const detailsRef = (0, react.useRef)(null);
235
+ const leaveTimerRef = (0, react.useRef)();
236
+ const keepHoverOpen = () => {
237
+ if (leaveTimerRef.current !== void 0) window.clearTimeout(leaveTimerRef.current);
238
+ leaveTimerRef.current = void 0;
239
+ setHovered(true);
240
+ };
241
+ const closeHoverAfterGrace = () => {
242
+ if (leaveTimerRef.current !== void 0) window.clearTimeout(leaveTimerRef.current);
243
+ leaveTimerRef.current = window.setTimeout(() => {
244
+ leaveTimerRef.current = void 0;
245
+ setHovered(false);
246
+ }, 220);
247
+ };
248
+ (0, react.useEffect)(() => () => {
249
+ if (leaveTimerRef.current !== void 0) window.clearTimeout(leaveTimerRef.current);
250
+ }, []);
251
+ const constrainDetailsToBoundary = () => {
252
+ const details = detailsRef.current;
253
+ const boundary = quoteRef.current?.closest(".dsh-side-chat-panel, [data-composer-seat], [data-chat-flow-kind]");
254
+ if (details === null) return;
255
+ details.style.setProperty("--dsh-side-chat-quote-offset-x", "0px");
256
+ const detailsRect = details.getBoundingClientRect();
257
+ const boundaryRect = boundary?.getBoundingClientRect();
258
+ const leftEdge = (boundaryRect?.left ?? 0) + 16;
259
+ const rightEdge = (boundaryRect?.right ?? window.innerWidth) - 16;
260
+ const offset = detailsRect.left < leftEdge ? leftEdge - detailsRect.left : detailsRect.right > rightEdge ? rightEdge - detailsRect.right : 0;
261
+ details.style.setProperty("--dsh-side-chat-quote-offset-x", `${String(offset)}px`);
262
+ };
263
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
264
+ ref: quoteRef,
265
+ className: "dsh-side-chat-quote",
266
+ "aria-label": messages.selectedPassage,
267
+ "data-expanded": expanded || void 0,
268
+ "data-hovered": hovered || void 0,
269
+ onMouseEnter: () => {
270
+ keepHoverOpen();
271
+ constrainDetailsToBoundary();
272
+ },
273
+ onMouseLeave: closeHoverAfterGrace,
274
+ onFocusCapture: constrainDetailsToBoundary,
275
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
276
+ className: "dsh-side-chat-quote-chip",
277
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
278
+ type: "button",
279
+ className: "dsh-side-chat-quote-trigger",
280
+ "aria-expanded": expanded,
281
+ "aria-label": `${expanded ? messages.collapse : messages.expand}: ${messages.selectedPassage}`,
282
+ onClick: () => {
283
+ setExpanded((value) => !value);
284
+ },
285
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
286
+ className: "dsh-side-chat-quote-icon",
287
+ viewBox: "0 0 24 24",
288
+ "aria-hidden": "true",
289
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M21 15a4 4 0 0 1-4 4H7l-4 4V7a4 4 0 0 1 4-4h10a4 4 0 0 1 4 4Z" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 8h8M8 12h5" })]
290
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: messages.selectionAttachments(selections.length) })]
291
+ }), onRemove !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
292
+ type: "button",
293
+ className: "dsh-side-chat-quote-remove",
294
+ "aria-label": messages.removeSelection,
295
+ onClick: onRemove,
296
+ children: "×"
297
+ })]
298
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
299
+ ref: detailsRef,
300
+ className: "dsh-side-chat-quote-details",
301
+ role: "tooltip",
302
+ children: selections.map((selection, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
303
+ className: "dsh-side-chat-quote-detail",
304
+ children: [
305
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
306
+ className: "dsh-side-chat-quote-details-header",
307
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: [
308
+ String(index + 1),
309
+ ". ",
310
+ messages.selectionPreviewLabel,
311
+ ":"
312
+ ] })
313
+ }),
314
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: selection.text }),
315
+ selection.comment !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
316
+ className: "dsh-side-chat-quote-comment",
317
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: [messages.selectionCommentLabel, ":"] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: selection.comment })]
318
+ })
319
+ ]
320
+ }, `${String(index)}-${selection.text}`))
321
+ })]
322
+ });
323
+ }
324
+ //#endregion
325
+ //#region src/client/parent-composer/ParentConversationAnnotations.tsx
326
+ function currentLocale() {
327
+ return navigator.language.toLowerCase().startsWith("zh") ? "zh-CN" : "en";
328
+ }
329
+ /** The interactive annotation capsule occupying the reserved first composer row. */
330
+ function ParentComposerAnnotations({ input, onRemove, locale = currentLocale() }) {
331
+ const annotations = conversationAnnotations(input);
332
+ if (annotations.length === 0) return null;
333
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
334
+ className: "dsh-side-chat-parent-annotation-dock",
335
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionQuote, {
336
+ selections: annotations,
337
+ messages: SIDE_CHAT_MESSAGES[locale],
338
+ onRemove
339
+ })
340
+ });
341
+ }
342
+ function contentText$1(content) {
343
+ return content.map((block) => {
344
+ if (typeof block !== "object" || block === null) return "";
345
+ const value = block;
346
+ return value.type === "text" && typeof value.text === "string" ? value.text : "";
347
+ }).join("");
348
+ }
349
+ function visibleMessage(message) {
350
+ return /^<user_question>\n?([\s\S]*?)\n?<\/user_question>$/u.exec(message)?.[1]?.trim() ?? message;
351
+ }
352
+ function replaceTextContent(content, message) {
353
+ let replaced = false;
354
+ const next = content.flatMap((block) => {
355
+ if (typeof block !== "object" || block === null) return [block];
356
+ const value = block;
357
+ if (value.type !== "text" || typeof value.text !== "string") return [block];
358
+ if (replaced) return [];
359
+ replaced = true;
360
+ return [{
361
+ ...value,
362
+ text: message
363
+ }];
364
+ });
365
+ return replaced ? next : [{
366
+ type: "text",
367
+ text: message
368
+ }, ...next];
369
+ }
370
+ /** Wrap DSH's own user renderer only when this plugin's durable prefix exists. */
371
+ function annotatedUserMessageRenderer(Original) {
372
+ return function AnnotatedUserMessageRenderer(props) {
373
+ const parsed = parseAnnotatedConversationPrompt(contentText$1(props.node.data.content));
374
+ if (parsed === void 0) return (0, react.createElement)(Original, props);
375
+ const node = {
376
+ ...props.node,
377
+ data: {
378
+ ...props.node.data,
379
+ content: replaceTextContent(props.node.data.content, visibleMessage(parsed.message))
380
+ }
381
+ };
382
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
383
+ className: "dsh-side-chat-parent-user-message",
384
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionQuote, {
385
+ selections: parsed.annotations,
386
+ messages: SIDE_CHAT_MESSAGES[currentLocale()]
387
+ }), (0, react.createElement)(Original, {
388
+ ...props,
389
+ node
390
+ })]
391
+ });
392
+ };
393
+ }
394
+ /** Mount the composer capsule and a thin wrapper around DSH's user renderers. */
395
+ function mountParentConversationAnnotations(ctx, removeAnnotations) {
396
+ const slots = ctx.slots;
397
+ const removeDock = slots.inject("conversation.input.dock", () => slots.register({
398
+ name: "conversation.input.dock",
399
+ id: "dsh-side-chat-annotations",
400
+ order: -100
401
+ }, ({ input }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ParentComposerAnnotations, {
402
+ input,
403
+ onRemove: removeAnnotations
404
+ })));
405
+ const shadow = (key) => slots.inject("conversation.chat.node", () => {
406
+ const ShadowedUserMessage = (props) => {
407
+ const original = slots.entries("conversation.chat.node").find((entry) => entry.options.key === key && entry.component !== ShadowedUserMessage && (entry.options.priority ?? 0) >= 0)?.component;
408
+ if (original === void 0) return null;
409
+ const Renderer = annotatedUserMessageRenderer(original);
410
+ return (0, react.createElement)(Renderer, props);
411
+ };
412
+ return slots.register({
413
+ name: "conversation.chat.node",
414
+ key,
415
+ priority: -100,
416
+ locale: "conversation"
417
+ }, ShadowedUserMessage);
418
+ });
419
+ const removeUser = shadow("user");
420
+ const removeSteering = shadow("steering");
421
+ return () => {
422
+ removeSteering();
423
+ removeUser();
424
+ removeDock();
425
+ };
426
+ }
11
427
  //#endregion
12
428
  //#region src/shared/observable.ts
13
429
  /** Immutable-value observable with contained subscriber failures. */
@@ -46,31 +462,6 @@ window.__ModuleLoader__.load({
46
462
  this.listeners.clear();
47
463
  }
48
464
  };
49
- //#endregion
50
- //#region src/client/parent-composer/add-to-conversation.ts
51
- function escapeXmlText(value) {
52
- return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
53
- }
54
- /** Add the selected quote to the first child prompt. */
55
- function buildSideChatPrompt(selection, question) {
56
- const trimmed = question.trim();
57
- if (selection === void 0) return [{
58
- type: "text",
59
- text: trimmed
60
- }];
61
- return [{
62
- type: "text",
63
- text: [
64
- `<selected_context source="current-conversation" event-seq="${selection.atSeq}">`,
65
- escapeXmlText(selection.text),
66
- "</selected_context>",
67
- "",
68
- "<user_question>",
69
- escapeXmlText(trimmed),
70
- "</user_question>"
71
- ].join("\n")
72
- }];
73
- }
74
465
  Object.freeze({
75
466
  repository: "https://github.com/deepseek-ai/deepseek-harness",
76
467
  npmPackage: "@deepseek-ai/dsh",
@@ -4784,102 +5175,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4784
5175
  };
4785
5176
  }
4786
5177
  //#endregion
4787
- //#region src/client/panel/messages.ts
4788
- const SIDE_CHAT_MESSAGES = Object.freeze({
4789
- en: Object.freeze({
4790
- title: "Side Chat",
4791
- close: "Close Side Chat",
4792
- placeholder: "Ask about this in a Side Chat",
4793
- send: "Send",
4794
- selectedPassage: "Selected passage",
4795
- selectionAttachment: "1 annotation",
4796
- selectionPreviewLabel: "Selected text",
4797
- removeSelection: "Remove annotation",
4798
- expand: "Expand",
4799
- collapse: "Collapse",
4800
- copy: "Copy",
4801
- temporary: "Archived when closed; history remains on disk",
4802
- referenceOnly: "Inherits the complete parent conversation prefix",
4803
- cannotReopen: "No reopen action",
4804
- sharedWorkspace: "Shares the parent workspace",
4805
- retry: "Retry",
4806
- genericError: "Side Chat error",
4807
- closeError: "Could not close the Side Chat"
4808
- }),
4809
- "zh-CN": Object.freeze({
4810
- title: "侧边对话",
4811
- close: "关闭侧边对话",
4812
- placeholder: "在侧边对话中询问这段内容",
4813
- send: "发送",
4814
- selectedPassage: "所选段落",
4815
- selectionAttachment: "1 条引用",
4816
- selectionPreviewLabel: "所选文本",
4817
- removeSelection: "移除引用",
4818
- expand: "展开",
4819
- collapse: "收起",
4820
- copy: "复制",
4821
- temporary: "关闭时归档;历史仍保存在磁盘上",
4822
- referenceOnly: "完整继承父会话对话前缀",
4823
- cannotReopen: "不提供重新打开操作",
4824
- sharedWorkspace: "与父会话共享工作区",
4825
- retry: "重试",
4826
- genericError: "侧边对话错误",
4827
- closeError: "无法关闭侧边对话"
4828
- })
4829
- });
4830
- //#endregion
4831
- //#region src/client/panel/SelectionQuote.tsx
4832
- /** Selected passage displayed separately from the user's first question. */
4833
- function SelectionQuote({ selection, messages, onCopy, onRemove }) {
4834
- const [expanded, setExpanded] = (0, react.useState)(false);
4835
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
4836
- className: "dsh-side-chat-quote",
4837
- "aria-label": messages.selectedPassage,
4838
- "data-expanded": expanded || void 0,
4839
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4840
- className: "dsh-side-chat-quote-chip",
4841
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4842
- type: "button",
4843
- className: "dsh-side-chat-quote-trigger",
4844
- "aria-expanded": expanded,
4845
- "aria-label": `${expanded ? messages.collapse : messages.expand}: ${messages.selectedPassage}`,
4846
- onClick: () => {
4847
- setExpanded((value) => !value);
4848
- },
4849
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
4850
- className: "dsh-side-chat-quote-icon",
4851
- viewBox: "0 0 24 24",
4852
- "aria-hidden": "true",
4853
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M21 15a4 4 0 0 1-4 4H7l-4 4V7a4 4 0 0 1 4-4h10a4 4 0 0 1 4 4Z" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 8h8M8 12h5" })]
4854
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: messages.selectionAttachment })]
4855
- }), onRemove !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4856
- type: "button",
4857
- className: "dsh-side-chat-quote-remove",
4858
- "aria-label": messages.removeSelection,
4859
- onClick: onRemove,
4860
- children: "×"
4861
- })]
4862
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4863
- className: "dsh-side-chat-quote-details",
4864
- role: "tooltip",
4865
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4866
- className: "dsh-side-chat-quote-details-header",
4867
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: [
4868
- "1. ",
4869
- messages.selectionPreviewLabel,
4870
- ":"
4871
- ] }), onCopy !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4872
- type: "button",
4873
- onClick: () => {
4874
- onCopy(selection.text);
4875
- },
4876
- children: messages.copy
4877
- })]
4878
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: selection.text })]
4879
- })]
4880
- });
4881
- }
4882
- //#endregion
4883
5178
  //#region src/client/panel/SendIcon.tsx
4884
5179
  /** Arrow used by DSH's native 34px primary send button. */
4885
5180
  function SendIcon() {
@@ -4958,7 +5253,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4958
5253
  }
4959
5254
  //#endregion
4960
5255
  //#region src/client/panel/SideChatPanel.tsx
4961
- function SideChatPanel({ state, locale = "en", embeddedConversation, onDraftChange, onFirstSend, onClose, onRetry, onFocusParent, onCopySelection, onRemoveSelection }) {
5256
+ function SideChatPanel({ state, locale = "en", embeddedConversation, onDraftChange, onFirstSend, onClose, onRetry, onFocusParent, onRemoveSelection }) {
4962
5257
  const messages = SIDE_CHAT_MESSAGES[locale];
4963
5258
  const [submitting, setSubmitting] = (0, react.useState)(false);
4964
5259
  const draftRef = useAutoGrowingTextarea(state.draft);
@@ -5004,9 +5299,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5004
5299
  },
5005
5300
  children: [
5006
5301
  state.selection !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionQuote, {
5007
- selection: state.selection,
5302
+ selections: [state.selection],
5008
5303
  messages,
5009
- ...onCopySelection === void 0 ? {} : { onCopy: onCopySelection },
5010
5304
  ...onRemoveSelection === void 0 ? {} : { onRemove: onRemoveSelection }
5011
5305
  }),
5012
5306
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
@@ -5153,17 +5447,104 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5153
5447
  }
5154
5448
  //#endregion
5155
5449
  //#region src/client/selection/SelectionActions.tsx
5156
- function SelectionActions({ selection, askDisabledReason, onAskInSideChat, onDismiss }) {
5450
+ function clamp(value, minimum, maximum) {
5451
+ return Math.min(Math.max(minimum, value), Math.max(minimum, maximum));
5452
+ }
5453
+ function SelectionActions({ selection, askDisabledReason, annotationNumber = 1, onAddToChat, onMoreDetails, onAskInSideChat, onAnnotationEditorChange, onDismiss }) {
5454
+ const [editingAnnotation, setEditingAnnotation] = (0, react.useState)(false);
5455
+ const [comment, setComment] = (0, react.useState)("");
5456
+ const commentRef = (0, react.useRef)(null);
5157
5457
  const center = selection.rect.x + selection.rect.width / 2;
5158
5458
  const style = {
5159
5459
  left: Math.min(Math.max(8, center), selection.rect.viewportWidth - 8),
5160
5460
  top: selection.rect.y < 56 ? selection.rect.y + selection.rect.height + 8 : selection.rect.y - 8,
5161
5461
  transform: selection.rect.y < 56 ? "translate(0, 0)" : "translate(0, -100%)"
5162
5462
  };
5463
+ const editorWidth = Math.min(420, selection.rect.viewportWidth - 16);
5464
+ const editorAbove = selection.rect.y - 118;
5465
+ const editorStyle = {
5466
+ left: clamp(selection.rect.x + selection.rect.width + 28, 8, selection.rect.viewportWidth - editorWidth - 8),
5467
+ top: editorAbove >= 8 ? editorAbove : clamp(selection.rect.y + selection.rect.height + 12, 8, selection.rect.viewportHeight - 126),
5468
+ width: editorWidth
5469
+ };
5470
+ const markerStyle = {
5471
+ left: clamp(selection.rect.x + selection.rect.width - 10, 8, selection.rect.viewportWidth - 36),
5472
+ top: selection.rect.y >= 38 ? selection.rect.y - 34 : selection.rect.y + selection.rect.height + 6
5473
+ };
5163
5474
  const keepSelection = (event) => {
5164
5475
  event.preventDefault();
5165
5476
  };
5166
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5477
+ (0, react.useEffect)(() => {
5478
+ if (editingAnnotation) commentRef.current?.focus();
5479
+ }, [editingAnnotation]);
5480
+ const closeEditor = () => {
5481
+ setEditingAnnotation(false);
5482
+ setComment("");
5483
+ onAnnotationEditorChange?.(false);
5484
+ };
5485
+ const saveAnnotation = () => {
5486
+ const trimmed = comment.trim();
5487
+ onAddToChat(selection, trimmed.length === 0 ? void 0 : trimmed);
5488
+ onAnnotationEditorChange?.(false);
5489
+ onDismiss();
5490
+ };
5491
+ const submitAnnotation = (event) => {
5492
+ event.preventDefault();
5493
+ saveAnnotation();
5494
+ };
5495
+ const annotationKeyDown = (event) => {
5496
+ if (event.key === "Escape") {
5497
+ event.preventDefault();
5498
+ event.stopPropagation();
5499
+ closeEditor();
5500
+ return;
5501
+ }
5502
+ if (event.key === "Enter" && !event.shiftKey) {
5503
+ event.preventDefault();
5504
+ saveAnnotation();
5505
+ }
5506
+ };
5507
+ if (editingAnnotation) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5508
+ className: "dsh-side-chat-selection-marker",
5509
+ "aria-hidden": "true",
5510
+ style: markerStyle,
5511
+ children: String(annotationNumber)
5512
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
5513
+ className: "dsh-side-chat-selection-comment",
5514
+ role: "dialog",
5515
+ "aria-label": "Add annotation comment",
5516
+ style: editorStyle,
5517
+ onSubmit: submitAnnotation,
5518
+ onMouseDown: (event) => {
5519
+ event.stopPropagation();
5520
+ },
5521
+ onKeyUp: (event) => {
5522
+ event.stopPropagation();
5523
+ },
5524
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
5525
+ ref: commentRef,
5526
+ value: comment,
5527
+ rows: 2,
5528
+ "aria-label": "Optional annotation comment",
5529
+ placeholder: "Add an optional comment…",
5530
+ onChange: (event) => {
5531
+ setComment(event.currentTarget.value);
5532
+ },
5533
+ onKeyDown: annotationKeyDown
5534
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5535
+ className: "dsh-side-chat-selection-comment-actions",
5536
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5537
+ type: "button",
5538
+ onClick: closeEditor,
5539
+ children: "Cancel"
5540
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5541
+ type: "submit",
5542
+ className: "dsh-side-chat-selection-comment-save",
5543
+ children: "Save"
5544
+ })]
5545
+ })]
5546
+ })] });
5547
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5167
5548
  className: "dsh-side-chat-selection-actions",
5168
5549
  role: "toolbar",
5169
5550
  "aria-label": "Selected conversation text actions",
@@ -5172,15 +5553,54 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5172
5553
  onKeyDown: (event) => {
5173
5554
  if (event.key === "Escape") onDismiss();
5174
5555
  },
5175
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5176
- type: "button",
5177
- disabled: askDisabledReason !== void 0,
5178
- title: askDisabledReason,
5179
- onClick: () => {
5180
- onAskInSideChat(selection);
5181
- onDismiss();
5182
- },
5183
- children: "Ask in side chat"
5556
+ children: [
5557
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5558
+ type: "button",
5559
+ onClick: () => {
5560
+ setEditingAnnotation(true);
5561
+ onAnnotationEditorChange?.(true);
5562
+ },
5563
+ children: "Add to chat"
5564
+ }),
5565
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5566
+ type: "button",
5567
+ disabled: askDisabledReason !== void 0,
5568
+ title: askDisabledReason,
5569
+ onClick: () => {
5570
+ onMoreDetails(selection);
5571
+ onDismiss();
5572
+ },
5573
+ children: "More details"
5574
+ }),
5575
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5576
+ type: "button",
5577
+ disabled: askDisabledReason !== void 0,
5578
+ title: askDisabledReason,
5579
+ onClick: () => {
5580
+ onAskInSideChat(selection);
5581
+ onDismiss();
5582
+ },
5583
+ children: "Ask in side chat"
5584
+ })
5585
+ ]
5586
+ });
5587
+ }
5588
+ //#endregion
5589
+ //#region src/client/panel/StopIcon.tsx
5590
+ /** Rounded-square stop glyph used by DSH's native primary action button. */
5591
+ function StopIcon() {
5592
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
5593
+ viewBox: "0 0 16 16",
5594
+ width: "16",
5595
+ height: "16",
5596
+ "aria-hidden": "true",
5597
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
5598
+ x: "3",
5599
+ y: "3",
5600
+ width: "10",
5601
+ height: "10",
5602
+ rx: "3",
5603
+ fill: "currentColor"
5184
5604
  })
5185
5605
  });
5186
5606
  }
@@ -5206,12 +5626,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5206
5626
  function firstSideChatQuestion(text) {
5207
5627
  return /<user_question>([\s\S]*?)<\/user_question>/u.exec(text)?.[1]?.trim() ?? text;
5208
5628
  }
5209
- function AssistantBlocks({ blocks }) {
5629
+ function AssistantBlocks({ blocks, streaming = false }) {
5210
5630
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: blocks.map((block, index) => {
5211
5631
  const key = `${block.kind}-${String(index)}`;
5212
- if (block.kind === "text") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5213
- className: "dsh-side-chat-message-text",
5214
- children: block.text
5632
+ if (block.kind === "text") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
5633
+ text: block.text,
5634
+ streaming
5215
5635
  }, key);
5216
5636
  if (block.kind === "reasoning") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
5217
5637
  className: "dsh-side-chat-reasoning",
@@ -5434,7 +5854,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5434
5854
  });
5435
5855
  }
5436
5856
  /** Functional rc.6 conversation surface bound to a non-current child Session. */
5437
- function ArchivedConversation({ face, inheritedThroughSeq, controller, selection, locale = "en", onCopySelection }) {
5857
+ function ArchivedConversation({ face, inheritedThroughSeq, controller, selection, locale = "en" }) {
5438
5858
  const snapshot = (0, react.useSyncExternalStore)((listener) => face.subscribe(listener), () => face.getSnapshot(), () => face.getSnapshot());
5439
5859
  const [draft, setDraft] = (0, react.useState)("");
5440
5860
  const [sending, setSending] = (0, react.useState)(false);
@@ -5481,9 +5901,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5481
5901
  nodes.map((node) => selection !== void 0 && node === annotatedUserNode ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5482
5902
  className: "dsh-side-chat-annotated-user-message",
5483
5903
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionQuote, {
5484
- selection,
5485
- messages: SIDE_CHAT_MESSAGES[locale],
5486
- ...onCopySelection === void 0 ? {} : { onCopy: onCopySelection }
5904
+ selections: [selection],
5905
+ messages: SIDE_CHAT_MESSAGES[locale]
5487
5906
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessageRow, { node })]
5488
5907
  }, `${node.kind}-${String(node.seq)}`) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessageRow, { node }, `${node.kind}-${String(node.seq)}`)),
5489
5908
  snapshot.partial !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
@@ -5492,7 +5911,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5492
5911
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5493
5912
  className: "dsh-side-chat-message-role",
5494
5913
  children: "Assistant"
5495
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssistantBlocks, { blocks: snapshot.partial.blocks })]
5914
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssistantBlocks, {
5915
+ blocks: snapshot.partial.blocks,
5916
+ streaming: true
5917
+ })]
5496
5918
  }),
5497
5919
  snapshot.runningCalls.map((call) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
5498
5920
  className: "dsh-side-chat-message dsh-side-chat-tool",
@@ -5531,19 +5953,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5531
5953
  event.currentTarget.form?.requestSubmit();
5532
5954
  }
5533
5955
  }
5534
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [snapshot.running && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5956
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: snapshot.running ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5535
5957
  type: "button",
5958
+ className: "dsh-side-chat-stop-button",
5959
+ "aria-label": "Stop generating",
5960
+ title: "Stop generating",
5536
5961
  onClick: () => {
5537
5962
  controller.cancel();
5538
5963
  },
5539
- children: "Stop"
5540
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5964
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StopIcon, {})
5965
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5541
5966
  type: "submit",
5542
5967
  className: "dsh-side-chat-send-button",
5543
- "aria-label": snapshot.running ? "Steer" : "Send",
5968
+ "aria-label": "Send",
5544
5969
  disabled: sending || draft.trim().length === 0,
5545
5970
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SendIcon, {})
5546
- })] })]
5971
+ }) })]
5547
5972
  })]
5548
5973
  });
5549
5974
  }
@@ -5716,6 +6141,29 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5716
6141
  return node !== void 0 && node.visibility === "visible" && node.kind === fragment.nodeKind && node.anchorSeq === fragment.seq && locationSettled(node.location);
5717
6142
  });
5718
6143
  }
6144
+ /** Add one selected passage to the native composer of its parent Session. */
6145
+ addSelectionToConversation(selection, comment) {
6146
+ if (this.currentSessionId() !== selection.parentSessionId) return false;
6147
+ const scope = this.ctx.sessions.scope(dshSessionId(selection.parentSessionId));
6148
+ if (scope === void 0) return false;
6149
+ return addSelectionToConversation(this.ctx.conversation.input.for(scope), selection, comment);
6150
+ }
6151
+ /** Number assigned to the next annotation shown beside the selected passage. */
6152
+ nextConversationAnnotationNumber() {
6153
+ const sessionId = this.currentSessionId();
6154
+ if (sessionId === void 0) return 1;
6155
+ const scope = this.ctx.sessions.scope(dshSessionId(sessionId));
6156
+ if (scope === void 0) return 1;
6157
+ return conversationAnnotations(this.ctx.conversation.input.for(scope).state.getSnapshot()).length + 1;
6158
+ }
6159
+ /** Remove the current Session's unsent selected-passage annotations. */
6160
+ removeConversationAnnotations() {
6161
+ const sessionId = this.currentSessionId();
6162
+ if (sessionId === void 0) return false;
6163
+ const scope = this.ctx.sessions.scope(dshSessionId(sessionId));
6164
+ if (scope === void 0) return false;
6165
+ return removeConversationAnnotations(this.ctx.conversation.input.for(scope));
6166
+ }
5719
6167
  async retain(sessionId) {
5720
6168
  const binding = await this.waitForBinding(dshSessionId(sessionId));
5721
6169
  await binding.session.open();
@@ -5787,10 +6235,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5787
6235
  }
5788
6236
  //#endregion
5789
6237
  //#region src/client/rc6/Rc6SideChatOverlay.tsx
6238
+ const MORE_DETAILS_PROMPT = "Please explain the selected passage in more detail.";
5790
6239
  function captureEvent(event) {
5791
6240
  if (event instanceof KeyboardEvent && event.key === "Escape") return false;
5792
6241
  const target = event.target;
5793
- return !(target instanceof Element && target.closest("[data-side-chat-panel], .dsh-side-chat-selection-actions") !== null);
6242
+ return !(target instanceof Element && target.closest([
6243
+ "[data-side-chat-panel]",
6244
+ ".dsh-side-chat-selection-actions",
6245
+ ".dsh-side-chat-selection-comment"
6246
+ ].join(", ")) !== null);
6247
+ }
6248
+ function focusParentComposer() {
6249
+ const input = document.querySelector([
6250
+ "[data-composer-seat] textarea",
6251
+ "[data-composer-seat] [role=\"textbox\"]",
6252
+ "[data-composer-seat] [contenteditable=\"true\"]"
6253
+ ].join(", "));
6254
+ if (input === null) return;
6255
+ input.focus();
6256
+ if (input instanceof HTMLTextAreaElement) {
6257
+ input.setSelectionRange(input.value.length, input.value.length);
6258
+ return;
6259
+ }
6260
+ const range = document.createRange();
6261
+ range.selectNodeContents(input);
6262
+ range.collapse(false);
6263
+ const selection = window.getSelection();
6264
+ selection?.removeAllRanges();
6265
+ selection?.addRange(range);
5794
6266
  }
5795
6267
  /** rc.6 compatibility surface: selection toolbar plus a non-current child conversation panel. */
5796
6268
  function Rc6SideChatOverlay({ controller, sessions }) {
@@ -5799,6 +6271,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5799
6271
  const [selection, setSelection] = (0, react.useState)(null);
5800
6272
  const captureGeneration = (0, react.useRef)(0);
5801
6273
  const mouseDownPoint = (0, react.useRef)(null);
6274
+ const annotationEditing = (0, react.useRef)(false);
5802
6275
  const capture = (0, react.useCallback)(async () => {
5803
6276
  const generation = ++captureGeneration.current;
5804
6277
  const parentSessionId = sessions.currentSessionId();
@@ -5835,6 +6308,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5835
6308
  x: event.clientX,
5836
6309
  y: event.clientY
5837
6310
  };
6311
+ annotationEditing.current = false;
5838
6312
  ++captureGeneration.current;
5839
6313
  setSelection(null);
5840
6314
  };
@@ -5845,6 +6319,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5845
6319
  if (start === null || Math.abs(event.clientX - start.x) > 2 || Math.abs(event.clientY - start.y) > 2 || event.detail > 1 || event.shiftKey) capture();
5846
6320
  };
5847
6321
  const onSelectionChange = () => {
6322
+ if (annotationEditing.current) return;
5848
6323
  const browserSelection = window.getSelection();
5849
6324
  if (browserSelection !== null && !browserSelection.isCollapsed) return;
5850
6325
  ++captureGeneration.current;
@@ -5872,25 +6347,46 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5872
6347
  }, [capture, controller]);
5873
6348
  (0, react.useEffect)(() => {
5874
6349
  ++captureGeneration.current;
6350
+ annotationEditing.current = false;
5875
6351
  setSelection(null);
5876
6352
  }, [currentSessionId]);
5877
6353
  const askDisabledReason = state.phase === "closed" ? void 0 : "Close the current Side Chat before starting another one.";
5878
6354
  const childFace = state.childSessionId === void 0 ? void 0 : sessions.face(state.childSessionId);
5879
6355
  const inheritedThroughSeq = state.inheritedThroughSeq;
5880
6356
  const locale = navigator.language.toLowerCase().startsWith("zh") ? "zh-CN" : "en";
5881
- const copySelection = (text) => {
5882
- navigator.clipboard.writeText(text).catch(() => {
5883
- sessions.notify({
5884
- kind: "warning",
5885
- text: "Could not copy the selected text."
5886
- });
5887
- });
5888
- };
5889
6357
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5890
6358
  className: "dsh-side-chat-overlay",
5891
6359
  children: [selection !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionActions, {
5892
6360
  selection,
6361
+ annotationNumber: sessions.nextConversationAnnotationNumber(),
5893
6362
  ...askDisabledReason === void 0 ? {} : { askDisabledReason },
6363
+ onAddToChat: (captured, comment) => {
6364
+ try {
6365
+ if (sessions.addSelectionToConversation(captured, comment)) focusParentComposer();
6366
+ else sessions.notify({
6367
+ kind: "warning",
6368
+ text: "Could not add the selection to the current chat."
6369
+ });
6370
+ } catch {
6371
+ sessions.notify({
6372
+ kind: "warning",
6373
+ text: "Could not add the selection to the current chat."
6374
+ });
6375
+ }
6376
+ setSelection(null);
6377
+ },
6378
+ onAnnotationEditorChange: (open) => {
6379
+ annotationEditing.current = open;
6380
+ },
6381
+ onMoreDetails: (captured) => {
6382
+ const opened = controller.openDraft({ selection: captured });
6383
+ if (!opened.ok) sessions.notify({
6384
+ kind: "warning",
6385
+ text: opened.error.message
6386
+ });
6387
+ else controller.sendFirst(MORE_DETAILS_PROMPT);
6388
+ setSelection(null);
6389
+ },
5894
6390
  onAskInSideChat: (captured) => {
5895
6391
  const opened = controller.openDraft({ selection: captured });
5896
6392
  if (!opened.ok) sessions.notify({
@@ -5900,6 +6396,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5900
6396
  setSelection(null);
5901
6397
  },
5902
6398
  onDismiss: () => {
6399
+ annotationEditing.current = false;
5903
6400
  setSelection(null);
5904
6401
  }
5905
6402
  }), state.phase !== "closed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideChatPanel, {
@@ -5910,8 +6407,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5910
6407
  inheritedThroughSeq,
5911
6408
  controller,
5912
6409
  ...state.selection === void 0 ? {} : { selection: state.selection },
5913
- locale,
5914
- onCopySelection: copySelection
6410
+ locale
5915
6411
  }) },
5916
6412
  onDraftChange: (draft) => {
5917
6413
  controller.setDraft(draft);
@@ -5922,7 +6418,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5922
6418
  onFocusParent: () => {
5923
6419
  if (state.parentSessionId !== void 0) sessions.openSession(state.parentSessionId);
5924
6420
  },
5925
- onCopySelection: copySelection,
5926
6421
  onRemoveSelection: () => {
5927
6422
  controller.clearSelection();
5928
6423
  }
@@ -5933,6 +6428,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5933
6428
  //#region src/client/apply.ts
5934
6429
  const name = "side-chat-client";
5935
6430
  const inject = [
6431
+ "conversation",
6432
+ "inputTriggers",
5936
6433
  "remote",
5937
6434
  "sessions",
5938
6435
  "slots"
@@ -5945,7 +6442,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5945
6442
  document.head.append(stylesheet);
5946
6443
  const clientCtx = ctx;
5947
6444
  const mounted = await mountArchivedRemote(clientCtx);
6445
+ const removeSelectionReferenceSource = clientCtx.inputTriggers.registerSource(selectionReferenceSource);
5948
6446
  const sessions = new Rc6SideChatSessions(clientCtx);
6447
+ const removeParentAnnotations = mountParentConversationAnnotations(clientCtx, () => {
6448
+ sessions.removeConversationAnnotations();
6449
+ });
5949
6450
  const controller = new SideChatController(mounted.remote, sessions);
5950
6451
  const removeOverlay = clientCtx.slots.inject("shell.overlay", () => clientCtx.slots.register({
5951
6452
  name: "shell.overlay",
@@ -5959,6 +6460,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5959
6460
  try {
5960
6461
  await controller.dispose();
5961
6462
  } finally {
6463
+ removeParentAnnotations();
6464
+ removeSelectionReferenceSource();
5962
6465
  removeOverlay();
5963
6466
  await mounted.dispose();
5964
6467
  stylesheet.remove();