@ahggg/dsh-side-chat 0.7.3 → 1.0.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 (79) hide show
  1. package/README.md +15 -12
  2. package/README.zh-CN.md +15 -12
  3. package/lib/client/apply.js +48 -32
  4. package/lib/client/contracts.d.ts +3 -58
  5. package/lib/client/dsh/ReadOnlyConversation.d.ts +10 -0
  6. package/lib/client/dsh/ReadOnlyConversation.js +91 -0
  7. package/lib/client/dsh/SideChatOverlay.d.ts +7 -0
  8. package/lib/client/{rc6/Rc6SideChatOverlay.js → dsh/SideChatOverlay.js} +26 -56
  9. package/lib/client/{rc6 → dsh}/context.d.ts +4 -6
  10. package/lib/client/dsh/conversation-store.d.ts +22 -0
  11. package/lib/client/dsh/conversation-store.js +19 -0
  12. package/lib/client/dsh/primitive-labels.d.ts +2 -0
  13. package/lib/client/dsh/primitive-labels.js +4 -0
  14. package/lib/client/{rc6 → dsh}/remote-adapter.d.ts +2 -2
  15. package/lib/client/dsh/remote-adapter.js +22 -0
  16. package/lib/client/dsh/sessions-adapter.d.ts +56 -0
  17. package/lib/client/dsh/sessions-adapter.js +185 -0
  18. package/lib/client/index.d.ts +2 -2
  19. package/lib/client/panel/SelectionQuote.js +8 -1
  20. package/lib/client/panel/SideChatErrorState.js +1 -1
  21. package/lib/client/panel/SideChatModelSelect.js +37 -18
  22. package/lib/client/panel/SideChatPanel.js +12 -5
  23. package/lib/client/panel/messages.d.ts +1 -1
  24. package/lib/client/panel/messages.js +8 -8
  25. package/lib/client/parent-composer/ParentConversationAnnotations.d.ts +3 -2
  26. package/lib/client/parent-composer/ParentConversationAnnotations.js +50 -30
  27. package/lib/client/parent-composer/add-to-conversation.d.ts +14 -28
  28. package/lib/client/parent-composer/add-to-conversation.js +131 -545
  29. package/lib/client/parent-composer/annotation-persistence.d.ts +8 -8
  30. package/lib/client/parent-composer/annotation-persistence.js +106 -102
  31. package/lib/client/parent-composer/composer-reference.d.ts +17 -55
  32. package/lib/client/parent-composer/composer-reference.js +20 -72
  33. package/lib/client/parent-composer/referenced-conversation.d.ts +5 -7
  34. package/lib/client/parent-composer/referenced-conversation.js +21 -73
  35. package/lib/client/selection/ConversationAnnotationMarkers.js +5 -1
  36. package/lib/client/selection/SelectionActions.js +2 -1
  37. package/lib/client/selection/conversation-dom.d.ts +5 -0
  38. package/lib/client/selection/conversation-dom.js +24 -0
  39. package/lib/client/selection/selection-controller.d.ts +1 -1
  40. package/lib/client/selection/selection-controller.js +7 -3
  41. package/lib/client/selection/selection-normalizer.js +1 -1
  42. package/lib/client/side-chat-controller.d.ts +28 -41
  43. package/lib/client/side-chat-controller.js +245 -337
  44. package/lib/client.js +81 -52
  45. package/lib/host/index.d.ts +1 -1
  46. package/lib/host/index.js +1 -1
  47. package/lib/host/read-only-chat-service.d.ts +30 -0
  48. package/lib/host/read-only-chat-service.js +314 -0
  49. package/lib/index.d.ts +16 -8
  50. package/lib/index.js +34 -13
  51. package/lib/remote.d.ts +23 -14
  52. package/lib/remote.js +2 -5
  53. package/lib/shared/constants.d.ts +0 -13
  54. package/lib/shared/constants.js +0 -13
  55. package/lib/shared/contracts.d.ts +52 -19
  56. package/lib/shared/contracts.js +2 -3
  57. package/lib/shared/error-codes.d.ts +1 -1
  58. package/lib/shared/error-codes.js +2 -2
  59. package/lib/shared/{archived-wire.d.ts → side-chat-wire.d.ts} +109 -20
  60. package/lib/shared/side-chat-wire.js +34 -0
  61. package/lib/typert.d.ts +3 -68
  62. package/lib/typert.js +60 -4
  63. package/package.json +76 -56
  64. package/lib/client/rc6/ArchivedConversation.d.ts +0 -14
  65. package/lib/client/rc6/ArchivedConversation.js +0 -231
  66. package/lib/client/rc6/Rc6SideChatOverlay.d.ts +0 -7
  67. package/lib/client/rc6/SideChatTool.d.ts +0 -22
  68. package/lib/client/rc6/SideChatTool.js +0 -404
  69. package/lib/client/rc6/primitive-labels.d.ts +0 -7
  70. package/lib/client/rc6/primitive-labels.js +0 -60
  71. package/lib/client/rc6/remote-adapter.js +0 -34
  72. package/lib/client/rc6/runtime-compat.d.ts +0 -120
  73. package/lib/client/rc6/runtime-compat.js +0 -187
  74. package/lib/client/rc6/sessions-adapter.d.ts +0 -64
  75. package/lib/client/rc6/sessions-adapter.js +0 -387
  76. package/lib/host/archived-fork-service.d.ts +0 -28
  77. package/lib/host/archived-fork-service.js +0 -309
  78. package/lib/shared/archived-wire.js +0 -47
  79. /package/lib/client/{rc6 → dsh}/context.js +0 -0
@@ -1,8 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { createElement, useLayoutEffect, useRef } from 'react';
3
+ import { SessionId } from '../../shared/contracts.js';
3
4
  import { SIDE_CHAT_MESSAGES } from '../panel/messages.js';
4
5
  import { SelectionQuote } from '../panel/SelectionQuote.js';
5
- import { conversationAnnotations, parseAnnotatedConversationPrompt, } from './add-to-conversation.js';
6
+ import { annotationMessageText, conversationAnnotations, parseAnnotatedConversationPrompt, } from './add-to-conversation.js';
6
7
  import { parseReferencedConversationPrompt, } from './referenced-conversation.js';
7
8
  function currentLocale() {
8
9
  return navigator.language.toLowerCase().startsWith('zh') ? 'zh-CN' : 'en';
@@ -16,24 +17,49 @@ export function ParentComposerAnnotations({ input, onRemove, locale = currentLoc
16
17
  const dock = dockRef.current;
17
18
  const seat = dock?.closest('[data-composer-seat]');
18
19
  const chip = dock?.querySelector('.dsh-side-chat-quote-chip');
19
- if (seat === undefined || chip === undefined || seat === null || chip === null)
20
+ if (dock === null || seat === undefined || chip === undefined || seat === null || chip === null)
20
21
  return;
21
22
  // The durable host reference stays in Lexical's document flow. Match its
22
23
  // occupied width to this visible overlay so the caret starts at the edge
23
24
  // users see instead of after the longer internal serialization label.
24
- const syncWidth = () => {
25
+ const syncPosition = () => {
25
26
  const width = chip.getBoundingClientRect().width;
26
27
  if (width > 0)
27
28
  seat.style.setProperty(ANNOTATION_CHIP_WIDTH_PROPERTY, `${String(width)}px`);
29
+ const reference = seat.querySelector('[data-composer-chip="dsh-side-chat-selection"]');
30
+ if (reference === null)
31
+ return;
32
+ const referenceRect = reference.getBoundingClientRect();
33
+ const dockRect = dock.getBoundingClientRect();
34
+ if (Number.isFinite(referenceRect.left) && Number.isFinite(dockRect.left)) {
35
+ dock.style.setProperty('--annotation-left', `${referenceRect.left - dockRect.left}px`);
36
+ dock.style.setProperty('--annotation-top', `${referenceRect.top - dockRect.top}px`);
37
+ }
28
38
  };
29
- syncWidth();
30
- const observer = typeof ResizeObserver === 'undefined' ? undefined : new ResizeObserver(syncWidth);
39
+ let frame;
40
+ const schedule = () => {
41
+ if (frame !== undefined)
42
+ return;
43
+ frame = window.requestAnimationFrame(() => { frame = undefined; syncPosition(); });
44
+ };
45
+ syncPosition();
46
+ const observer = typeof ResizeObserver === 'undefined' ? undefined : new ResizeObserver(schedule);
31
47
  observer?.observe(chip);
48
+ observer?.observe(seat);
49
+ const mutations = new MutationObserver(schedule);
50
+ mutations.observe(seat, { childList: true, characterData: true, subtree: true });
51
+ seat.addEventListener('scroll', schedule, true);
52
+ window.addEventListener('resize', schedule);
32
53
  return () => {
54
+ if (frame !== undefined)
55
+ window.cancelAnimationFrame(frame);
33
56
  observer?.disconnect();
57
+ mutations.disconnect();
58
+ seat.removeEventListener('scroll', schedule, true);
59
+ window.removeEventListener('resize', schedule);
34
60
  seat.style.removeProperty(ANNOTATION_CHIP_WIDTH_PROPERTY);
35
61
  };
36
- }, [annotations.length, locale]);
62
+ }, [input, locale]);
37
63
  if (annotations.length === 0)
38
64
  return null;
39
65
  return (_jsx("div", { ref: dockRef, className: "dsh-side-chat-parent-annotation-dock", children: _jsx(SelectionQuote, { selections: annotations, messages: SIDE_CHAT_MESSAGES[locale], onRemove: onRemove }) }));
@@ -46,10 +72,6 @@ function contentText(content) {
46
72
  return value.type === 'text' && typeof value.text === 'string' ? value.text : '';
47
73
  }).join('');
48
74
  }
49
- function visibleMessage(message) {
50
- const wrapped = /^<user_question>\n?([\s\S]*?)\n?<\/user_question>$/u.exec(message);
51
- return wrapped?.[1]?.trim() ?? message;
52
- }
53
75
  function replaceTextContent(content, message) {
54
76
  let replaced = false;
55
77
  const next = content.flatMap((block) => {
@@ -68,29 +90,25 @@ function replaceTextContent(content, message) {
68
90
  function parsePluginPrompt(text) {
69
91
  let message = text;
70
92
  let annotations;
71
- let reference;
72
- for (let index = 0; index < 2; index += 1) {
93
+ const references = [];
94
+ while (message.length > 0) {
73
95
  const annotated = annotations === undefined ? parseAnnotatedConversationPrompt(message) : undefined;
74
96
  if (annotated !== undefined) {
75
97
  annotations = annotated.annotations;
76
98
  message = annotated.message;
77
99
  continue;
78
100
  }
79
- const referenced = reference === undefined ? parseReferencedConversationPrompt(message) : undefined;
101
+ const referenced = parseReferencedConversationPrompt(message);
80
102
  if (referenced !== undefined) {
81
- reference = referenced.reference;
103
+ references.push(referenced.reference);
82
104
  message = referenced.message;
83
105
  continue;
84
106
  }
85
107
  break;
86
108
  }
87
- if (annotations === undefined && reference === undefined)
109
+ if (annotations === undefined && references.length === 0)
88
110
  return;
89
- return {
90
- ...(annotations === undefined ? {} : { annotations }),
91
- ...(reference === undefined ? {} : { reference }),
92
- message,
93
- };
111
+ return { ...(annotations === undefined ? {} : { annotations }), references, message };
94
112
  }
95
113
  /** Wrap DSH's own user renderer only when this plugin's durable prefix exists. */
96
114
  export function annotatedUserMessageRenderer(Original) {
@@ -98,19 +116,16 @@ export function annotatedUserMessageRenderer(Original) {
98
116
  const parsed = parsePluginPrompt(contentText(props.node.data.content));
99
117
  if (parsed === undefined)
100
118
  return createElement(Original, props);
101
- const body = visibleMessage(parsed.message);
102
- const visible = parsed.reference === undefined
103
- ? body
104
- : [`@${parsed.reference.title}`, body].filter(part => part.length > 0).join('\n\n');
119
+ const body = parsed.annotations === undefined ? parsed.message : annotationMessageText(parsed.message);
120
+ const visible = [...parsed.references.map(reference => `@${reference.title}`), body]
121
+ .filter(part => part.length > 0).join('\n\n');
105
122
  const existingLabels = props.node.data.referenceLabels ?? [];
106
123
  const node = {
107
124
  ...props.node,
108
125
  data: {
109
126
  ...props.node.data,
110
127
  content: replaceTextContent(props.node.data.content, visible),
111
- ...(parsed.reference === undefined
112
- ? {}
113
- : { referenceLabels: [...new Set([parsed.reference.title, ...existingLabels])] }),
128
+ referenceLabels: [...new Set([...parsed.references.map(reference => reference.title), ...existingLabels])],
114
129
  },
115
130
  };
116
131
  const original = createElement(Original, { ...props, node });
@@ -128,8 +143,10 @@ export function mountParentConversationAnnotations(ctx, removeAnnotations) {
128
143
  // This zero-height projection must follow Todo (0), Goal (10), and Queue
129
144
  // (20), so its absolute child remains anchored to the input card below.
130
145
  order: 30,
131
- }, ({ input }) => (_jsx(ParentComposerAnnotations, { input: input, onRemove: removeAnnotations }))));
146
+ }, ({ input, session }) => (_jsx(ParentComposerAnnotations, { input: input, onRemove: () => removeAnnotations(SessionId(session.sessionId)) }))));
132
147
  const shadow = (key) => slots.inject('conversation.chat.node', () => {
148
+ let cachedOriginal;
149
+ let CachedRenderer;
133
150
  const ShadowedUserMessage = (props) => {
134
151
  // Built-in keyed renderers can register after this declaration callback.
135
152
  // Resolve the next-priority renderer at render time so load order does
@@ -141,8 +158,11 @@ export function mountParentConversationAnnotations(ctx, removeAnnotations) {
141
158
  ?.component;
142
159
  if (original === undefined)
143
160
  return null;
144
- const Renderer = annotatedUserMessageRenderer(original);
145
- return createElement(Renderer, props);
161
+ if (original !== cachedOriginal || CachedRenderer === undefined) {
162
+ cachedOriginal = original;
163
+ CachedRenderer = annotatedUserMessageRenderer(cachedOriginal);
164
+ }
165
+ return createElement(CachedRenderer, props);
146
166
  };
147
167
  return slots.register({
148
168
  name: 'conversation.chat.node',
@@ -1,50 +1,36 @@
1
1
  import type { ConversationSelection, SideChatPromptPart } from '../../shared/contracts.js';
2
2
  import type { ParentComposerInput, ParentComposerInputSnapshot, SelectionReferenceSource } from './composer-reference.js';
3
3
  export type { ParentComposerInput, ParentComposerInputSnapshot, ParentComposerOccurrence, ParentConversationService, SelectionReferenceSource, } from './composer-reference.js';
4
+ export declare const SELECTION_REFERENCE_SOURCE = "dsh-side-chat-selection";
4
5
  export declare const SELECTION_REFERENCE_LABEL = "__dsh_side_chat_annotations__";
5
6
  export interface ConversationAnnotation {
6
7
  readonly text: string;
7
8
  readonly comment?: string;
8
9
  }
9
- export interface ConversationSelectionAnnotation extends ConversationAnnotation {
10
- /** Zero-based position in the aggregated composer annotation list. */
11
- readonly annotationIndex: number;
10
+ interface StoredConversationAnnotation extends ConversationAnnotation {
12
11
  readonly selection: ConversationSelection;
13
12
  }
13
+ export interface ConversationSelectionAnnotation extends StoredConversationAnnotation {
14
+ readonly annotationIndex: number;
15
+ }
16
+ export declare function unescapeXmlText(value: string): string;
14
17
  export declare function decodeSelectionReference(ref: string): readonly ConversationAnnotation[];
15
- /** Read all plugin annotations represented by the current DSH input occurrence. */
16
18
  export declare function conversationAnnotations(snapshot: ParentComposerInputSnapshot): readonly ConversationAnnotation[];
17
- /** Read annotations that retain an exact source-selection anchor. */
18
19
  export declare function conversationSelectionAnnotations(snapshot: ParentComposerInputSnapshot): readonly ConversationSelectionAnnotation[];
19
- /** Remove every unsent plugin annotation while preserving the user's draft. */
20
- export declare function removeConversationAnnotations(input: ParentComposerInput): boolean;
21
- /** Reference codec used by DSH's native composer chip and submit pipeline. */
22
- export declare const selectionReferenceSource: SelectionReferenceSource;
23
- /** Add one passage to the parent composer's aggregated annotation occurrence. */
24
20
  export declare function addSelectionToConversation(input: ParentComposerInput, selection: ConversationSelection, comment?: string): boolean;
25
- /** Remove one unsent selected-passage annotation, retaining the aggregate when needed. */
21
+ export declare function removeConversationAnnotations(input: ParentComposerInput): boolean;
26
22
  export declare function removeConversationAnnotation(input: ParentComposerInput, annotationIndex: number): boolean;
27
- /** Replace the optional comment on one unsent selected-passage annotation. */
28
23
  export declare function updateConversationAnnotation(input: ParentComposerInput, annotationIndex: number, comment?: string): boolean;
29
- export interface ConversationAnnotationRecoveryRecord {
30
- readonly ref: string;
31
- readonly displayDraft: string;
32
- readonly mirrorDraft: string;
33
- readonly baseDraft: string;
34
- }
35
- /** Describe both the display draft and DSH's persisted clipboard projection. */
36
- export declare function conversationAnnotationRecoveryRecord(snapshot: ParentComposerInputSnapshot): ConversationAnnotationRecoveryRecord | undefined;
37
- /** Return the valid aggregated reference currently occupying the leading draft slot. */
38
- export declare function conversationAnnotationReference(snapshot: ParentComposerInputSnapshot): string | undefined;
39
- /** Remove the plugin-owned prefix when rc.6 restored its draft without occurrences. */
40
- export declare function removeOrphanedConversationAnnotationPlaceholder(input: ParentComposerInput): boolean;
41
- /** Rehydrate a lost occurrence over either its display draft or exact mirror projection. */
42
- export declare function restoreConversationAnnotationReference(input: ParentComposerInput, ref: string, expectedMirrorDraft?: string, expectedBaseDraft?: string): boolean;
24
+ export declare const selectionReferenceSource: SelectionReferenceSource;
43
25
  export interface AnnotatedConversationPrompt {
44
26
  readonly annotations: readonly ConversationAnnotation[];
45
27
  readonly message: string;
46
28
  }
47
- /** Parse the durable model form back into the user-facing annotation capsule. */
48
29
  export declare function parseAnnotatedConversationPrompt(text: string): AnnotatedConversationPrompt | undefined;
49
- /** Add the selected quote to the first child prompt. */
30
+ /** The first prompt uses the same durable annotation format as the main composer. */
50
31
  export declare function buildSideChatPrompt(selection: ConversationSelection | undefined, question: string): readonly SideChatPromptPart[];
32
+ /** Decode a question only after recognizing this plugin's annotation prefix. */
33
+ export declare function annotationMessageText(message: string): string;
34
+ /** One projection supplies both the annotation capsule and the visible question. */
35
+ export declare function parseSideChatPrompt(text: string): AnnotatedConversationPrompt | undefined;
36
+ export declare function sideChatQuestionText(text: string): string;