@adecore/agents-react 0.38.0 → 0.39.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.
- package/dist/agents/AgentModelLabel.d.ts +10 -0
- package/dist/agents/AgentModelLabel.js +97 -0
- package/dist/chat/ui/Composer.js +385 -360
- package/dist/chat/ui/Pickers.d.ts +2 -1
- package/dist/chat/ui/Pickers.js +126 -123
- package/dist/chat/ui/PromptEditor.d.ts +19 -0
- package/dist/chat/ui/PromptEditor.js +115 -0
- package/dist/chat/ui/Timeline.d.ts +2 -1
- package/dist/chat/ui/Timeline.js +13 -1
- package/dist/chat/ui/composer/ComposerControls.d.ts +3 -0
- package/dist/chat/ui/composer/ComposerControls.js +235 -38
- package/dist/chat/ui/composer/key-handler.d.ts +1 -1
- package/dist/chat/ui/composer/key-handler.js +3 -11
- package/dist/chat/ui/composer/prompt-picks.d.ts +4 -0
- package/dist/chat/ui/composer/prompt-picks.js +14 -0
- package/dist/chat/ui/composer/use-composer-menus.d.ts +4 -49
- package/dist/chat/ui/composer/use-composer-menus.js +65 -519
- package/dist/chat/ui/composer/use-prompt-menus.d.ts +73 -0
- package/dist/chat/ui/composer/use-prompt-menus.js +536 -0
- package/dist/chat/ui/index.d.ts +3 -0
- package/dist/chat/ui/index.js +2 -0
- package/dist/host-hooks.d.ts +2 -1
- package/dist/host-hooks.js +6 -0
- package/dist/host.d.ts +17 -1
- package/dist/index.d.ts +1 -1
- package/dist/locales/en/agent-chat.d.ts +1 -0
- package/dist/locales/en/agent-chat.js +1 -0
- package/dist/locales/nl/agent-chat.d.ts +1 -0
- package/dist/locales/nl/agent-chat.js +1 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/theme.css +3 -0
- package/package.json +8 -8
- package/src/agents/AgentModelLabel.tsx +40 -0
- package/src/chat/ui/Composer.tsx +12 -3
- package/src/chat/ui/Pickers.tsx +4 -1
- package/src/chat/ui/PromptEditor.tsx +130 -0
- package/src/chat/ui/Timeline.tsx +22 -1
- package/src/chat/ui/composer/ComposerControls.tsx +65 -15
- package/src/chat/ui/composer/key-handler.ts +3 -9
- package/src/chat/ui/composer/prompt-picks.ts +17 -0
- package/src/chat/ui/composer/use-composer-menus.ts +18 -275
- package/src/chat/ui/composer/use-prompt-menus.ts +341 -0
- package/src/chat/ui/index.ts +3 -0
- package/src/host-hooks.ts +9 -1
- package/src/host.ts +27 -1
- package/src/index.ts +2 -0
- package/src/locales/en/agent-chat.ts +1 -0
- package/src/locales/nl/agent-chat.ts +1 -0
- package/src/providers/index.ts +1 -0
- package/src/theme.css +3 -0
|
@@ -11,10 +11,11 @@ interface ModelPickerProps {
|
|
|
11
11
|
kbd?: string | null;
|
|
12
12
|
side?: 'top' | 'bottom';
|
|
13
13
|
trigger?: 'plain' | 'chip';
|
|
14
|
+
chipSize?: 'sm' | 'md';
|
|
14
15
|
finalFocus?: RefObject<HTMLElement | null>;
|
|
15
16
|
footer?: ReactNode;
|
|
16
17
|
}
|
|
17
|
-
export declare function ModelPicker({ providers, provider, selection, open, onOpenChange, onChange, kbd, side, trigger, finalFocus, footer }: ModelPickerProps): import("react").JSX.Element;
|
|
18
|
+
export declare function ModelPicker({ providers, provider, selection, open, onOpenChange, onChange, kbd, side, trigger, chipSize, finalFocus, footer }: ModelPickerProps): import("react").JSX.Element;
|
|
18
19
|
export declare function StashPicker({ onRestore }: {
|
|
19
20
|
onRestore(prompt: StashedPrompt): void;
|
|
20
21
|
}): import("react").JSX.Element | null;
|
package/dist/chat/ui/Pickers.js
CHANGED
|
@@ -23,7 +23,7 @@ const triggerClass = 'flex h-7 shrink-0 items-center gap-1 whitespace-nowrap rou
|
|
|
23
23
|
* provider's model is also how a chat picks its provider; with one CLI the group headers drop.
|
|
24
24
|
*/
|
|
25
25
|
export function ModelPicker(t0) {
|
|
26
|
-
const $ = _c(
|
|
26
|
+
const $ = _c(50);
|
|
27
27
|
const {
|
|
28
28
|
providers,
|
|
29
29
|
provider,
|
|
@@ -34,115 +34,117 @@ export function ModelPicker(t0) {
|
|
|
34
34
|
kbd: t1,
|
|
35
35
|
side: t2,
|
|
36
36
|
trigger: t3,
|
|
37
|
+
chipSize: t4,
|
|
37
38
|
finalFocus,
|
|
38
39
|
footer
|
|
39
40
|
} = t0;
|
|
40
41
|
const kbd = t1 === undefined ? "/model" : t1;
|
|
41
42
|
const side = t2 === undefined ? "top" : t2;
|
|
42
43
|
const trigger = t3 === undefined ? "plain" : t3;
|
|
44
|
+
const chipSize = t4 === undefined ? "sm" : t4;
|
|
43
45
|
const host = useChatHost();
|
|
44
46
|
const {
|
|
45
47
|
t
|
|
46
48
|
} = useTranslation("agent-chat");
|
|
47
49
|
const [query, setQuery] = useState("");
|
|
48
50
|
const [legacyOpen, setLegacyOpen] = useState(false);
|
|
49
|
-
let
|
|
51
|
+
let t5;
|
|
50
52
|
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
51
|
-
|
|
52
|
-
$[0] =
|
|
53
|
+
t5 = new Set();
|
|
54
|
+
$[0] = t5;
|
|
53
55
|
} else {
|
|
54
|
-
|
|
56
|
+
t5 = $[0];
|
|
55
57
|
}
|
|
56
|
-
const [expanded, setExpanded] = useState(
|
|
58
|
+
const [expanded, setExpanded] = useState(t5);
|
|
57
59
|
const [index, setIndex] = useState(0);
|
|
58
60
|
const inputRef = useRef(null);
|
|
59
61
|
const listRef = useRef(null);
|
|
60
62
|
let owner;
|
|
61
|
-
let
|
|
63
|
+
let t6;
|
|
62
64
|
if ($[1] !== provider || $[2] !== providers || $[3] !== selection.model) {
|
|
63
|
-
let
|
|
65
|
+
let t7;
|
|
64
66
|
if ($[6] !== provider) {
|
|
65
|
-
|
|
67
|
+
t7 = entry => entry.kind === provider;
|
|
66
68
|
$[6] = provider;
|
|
67
|
-
$[7] =
|
|
69
|
+
$[7] = t7;
|
|
68
70
|
} else {
|
|
69
|
-
|
|
71
|
+
t7 = $[7];
|
|
70
72
|
}
|
|
71
|
-
owner = providers.find(
|
|
72
|
-
|
|
73
|
+
owner = providers.find(t7);
|
|
74
|
+
t6 = modelName(selection.model, owner?.models);
|
|
73
75
|
$[1] = provider;
|
|
74
76
|
$[2] = providers;
|
|
75
77
|
$[3] = selection.model;
|
|
76
78
|
$[4] = owner;
|
|
77
|
-
$[5] =
|
|
79
|
+
$[5] = t6;
|
|
78
80
|
} else {
|
|
79
81
|
owner = $[4];
|
|
80
|
-
|
|
82
|
+
t6 = $[5];
|
|
81
83
|
}
|
|
82
|
-
const current =
|
|
83
|
-
let
|
|
84
|
+
const current = t6;
|
|
85
|
+
let t7;
|
|
84
86
|
if ($[8] !== provider || $[9] !== providers || $[10] !== selection.model) {
|
|
85
|
-
|
|
87
|
+
t7 = agentChipOf(providers, provider, selection.model);
|
|
86
88
|
$[8] = provider;
|
|
87
89
|
$[9] = providers;
|
|
88
90
|
$[10] = selection.model;
|
|
89
|
-
$[11] =
|
|
91
|
+
$[11] = t7;
|
|
90
92
|
} else {
|
|
91
|
-
|
|
93
|
+
t7 = $[11];
|
|
92
94
|
}
|
|
93
|
-
const chip =
|
|
95
|
+
const chip = t7;
|
|
94
96
|
const grouped = providers.length > 1;
|
|
95
97
|
const trimmed = query.trim().toLowerCase();
|
|
96
98
|
const favorites = useChatPreferences(_temp);
|
|
97
|
-
let
|
|
99
|
+
let t8;
|
|
98
100
|
if ($[12] !== favorites) {
|
|
99
|
-
|
|
101
|
+
t8 = row => row?.kind === "model" && favorites[row.provider.kind]?.includes(row.model.slug) === true;
|
|
100
102
|
$[12] = favorites;
|
|
101
|
-
$[13] =
|
|
103
|
+
$[13] = t8;
|
|
102
104
|
} else {
|
|
103
|
-
|
|
105
|
+
t8 = $[13];
|
|
104
106
|
}
|
|
105
|
-
const starredHere =
|
|
106
|
-
let
|
|
107
|
+
const starredHere = t8;
|
|
108
|
+
let t9;
|
|
107
109
|
if ($[14] !== favorites) {
|
|
108
|
-
|
|
110
|
+
t9 = kind => favoriteModelsOf(favorites, kind);
|
|
109
111
|
$[14] = favorites;
|
|
110
|
-
$[15] =
|
|
112
|
+
$[15] = t9;
|
|
111
113
|
} else {
|
|
112
|
-
|
|
114
|
+
t9 = $[15];
|
|
113
115
|
}
|
|
114
116
|
const entries = pickerEntriesOf(inPickerOrder(providers), trimmed, legacyOpen, expanded, {
|
|
115
117
|
provider,
|
|
116
118
|
model: selection.model
|
|
117
|
-
},
|
|
119
|
+
}, t9);
|
|
118
120
|
const scope = useContext(ChatScopeContext);
|
|
119
121
|
const machine = useHostMachineLabel(scope?.id ?? "");
|
|
120
122
|
const reported = useReportedModels(provider);
|
|
121
|
-
let
|
|
123
|
+
let t10;
|
|
122
124
|
if ($[16] !== reported) {
|
|
123
|
-
|
|
125
|
+
t10 = entry_0 => modelRequirementOf(entry_0.model, entry_0.provider, reported);
|
|
124
126
|
$[16] = reported;
|
|
125
|
-
$[17] =
|
|
127
|
+
$[17] = t10;
|
|
126
128
|
} else {
|
|
127
|
-
|
|
129
|
+
t10 = $[17];
|
|
128
130
|
}
|
|
129
|
-
const requirementOf =
|
|
131
|
+
const requirementOf = t10;
|
|
130
132
|
const kindBefore = i => {
|
|
131
133
|
const before = entries[i - 1];
|
|
132
134
|
return before === undefined || before.kind === "legacy" ? undefined : before.provider.kind;
|
|
133
135
|
};
|
|
134
|
-
let
|
|
136
|
+
let t11;
|
|
135
137
|
if ($[18] !== requirementOf) {
|
|
136
|
-
|
|
138
|
+
t11 = entry_1 => entry_1.kind === "model" && requirementOf(entry_1) !== null ? [entry_1.provider.kind] : [];
|
|
137
139
|
$[18] = requirementOf;
|
|
138
|
-
$[19] =
|
|
140
|
+
$[19] = t11;
|
|
139
141
|
} else {
|
|
140
|
-
|
|
142
|
+
t11 = $[19];
|
|
141
143
|
}
|
|
142
|
-
const blockedKinds = new Set(entries.flatMap(
|
|
143
|
-
let
|
|
144
|
+
const blockedKinds = new Set(entries.flatMap(t11));
|
|
145
|
+
let t12;
|
|
144
146
|
if ($[20] !== onOpenChange) {
|
|
145
|
-
|
|
147
|
+
t12 = next => {
|
|
146
148
|
if (!next) {
|
|
147
149
|
setQuery("");
|
|
148
150
|
setLegacyOpen(false);
|
|
@@ -152,31 +154,31 @@ export function ModelPicker(t0) {
|
|
|
152
154
|
onOpenChange(next);
|
|
153
155
|
};
|
|
154
156
|
$[20] = onOpenChange;
|
|
155
|
-
$[21] =
|
|
157
|
+
$[21] = t12;
|
|
156
158
|
} else {
|
|
157
|
-
|
|
159
|
+
t12 = $[21];
|
|
158
160
|
}
|
|
159
|
-
const setOpen =
|
|
160
|
-
let
|
|
161
|
+
const setOpen = t12;
|
|
162
|
+
let t13;
|
|
161
163
|
if ($[22] === Symbol.for("react.memo_cache_sentinel")) {
|
|
162
|
-
|
|
164
|
+
t13 = () => {
|
|
163
165
|
listRef.current?.querySelector("[data-active=\"true\"]")?.scrollIntoView({
|
|
164
166
|
block: "nearest"
|
|
165
167
|
});
|
|
166
168
|
};
|
|
167
|
-
$[22] =
|
|
169
|
+
$[22] = t13;
|
|
168
170
|
} else {
|
|
169
|
-
|
|
171
|
+
t13 = $[22];
|
|
170
172
|
}
|
|
171
|
-
let
|
|
173
|
+
let t14;
|
|
172
174
|
if ($[23] !== index) {
|
|
173
|
-
|
|
175
|
+
t14 = [index];
|
|
174
176
|
$[23] = index;
|
|
175
|
-
$[24] =
|
|
177
|
+
$[24] = t14;
|
|
176
178
|
} else {
|
|
177
|
-
|
|
179
|
+
t14 = $[24];
|
|
178
180
|
}
|
|
179
|
-
useEffect(
|
|
181
|
+
useEffect(t13, t14);
|
|
180
182
|
const choose = entry_2 => {
|
|
181
183
|
if (!entry_2) {
|
|
182
184
|
return;
|
|
@@ -220,23 +222,23 @@ export function ModelPicker(t0) {
|
|
|
220
222
|
}
|
|
221
223
|
}
|
|
222
224
|
};
|
|
223
|
-
let
|
|
225
|
+
let t15;
|
|
224
226
|
if ($[25] !== current || $[26] !== owner || $[27] !== t) {
|
|
225
|
-
|
|
227
|
+
t15 = owner ? `${owner.name} · ${current}` : t("pickers.model.choose");
|
|
226
228
|
$[25] = current;
|
|
227
229
|
$[26] = owner;
|
|
228
230
|
$[27] = t;
|
|
229
|
-
$[28] =
|
|
231
|
+
$[28] = t15;
|
|
230
232
|
} else {
|
|
231
|
-
|
|
233
|
+
t15 = $[28];
|
|
232
234
|
}
|
|
233
|
-
const
|
|
234
|
-
let
|
|
235
|
-
if ($[29] !== chip || $[30] !==
|
|
236
|
-
|
|
235
|
+
const t16 = kbd ?? undefined;
|
|
236
|
+
let t17;
|
|
237
|
+
if ($[29] !== chip || $[30] !== chipSize || $[31] !== current || $[32] !== provider || $[33] !== trigger) {
|
|
238
|
+
t17 = trigger === "chip" ? /*#__PURE__*/_jsxs(Popover.Trigger, {
|
|
237
239
|
render: /*#__PURE__*/_jsx(Button, {
|
|
238
240
|
variant: "secondary",
|
|
239
|
-
size:
|
|
241
|
+
size: chipSize,
|
|
240
242
|
className: "min-w-0 shrink gap-1.5"
|
|
241
243
|
}),
|
|
242
244
|
children: [chip.mark === "logo" ? /*#__PURE__*/_jsx(ProviderLogo, {
|
|
@@ -271,73 +273,74 @@ export function ModelPicker(t0) {
|
|
|
271
273
|
})]
|
|
272
274
|
});
|
|
273
275
|
$[29] = chip;
|
|
274
|
-
$[30] =
|
|
275
|
-
$[31] =
|
|
276
|
-
$[32] =
|
|
277
|
-
$[33] =
|
|
276
|
+
$[30] = chipSize;
|
|
277
|
+
$[31] = current;
|
|
278
|
+
$[32] = provider;
|
|
279
|
+
$[33] = trigger;
|
|
280
|
+
$[34] = t17;
|
|
278
281
|
} else {
|
|
279
|
-
|
|
282
|
+
t17 = $[34];
|
|
280
283
|
}
|
|
281
|
-
let
|
|
282
|
-
if ($[
|
|
283
|
-
|
|
284
|
-
label:
|
|
285
|
-
kbd:
|
|
286
|
-
children:
|
|
284
|
+
let t18;
|
|
285
|
+
if ($[35] !== t15 || $[36] !== t16 || $[37] !== t17) {
|
|
286
|
+
t18 = /*#__PURE__*/_jsx(Tooltip, {
|
|
287
|
+
label: t15,
|
|
288
|
+
kbd: t16,
|
|
289
|
+
children: t17
|
|
287
290
|
});
|
|
288
|
-
$[34] = t14;
|
|
289
291
|
$[35] = t15;
|
|
290
292
|
$[36] = t16;
|
|
291
293
|
$[37] = t17;
|
|
294
|
+
$[38] = t18;
|
|
292
295
|
} else {
|
|
293
|
-
|
|
296
|
+
t18 = $[38];
|
|
294
297
|
}
|
|
295
|
-
let
|
|
296
|
-
if ($[
|
|
297
|
-
|
|
298
|
+
let t19;
|
|
299
|
+
if ($[39] !== finalFocus) {
|
|
300
|
+
t19 = finalFocus === undefined ? {} : {
|
|
298
301
|
finalFocus
|
|
299
302
|
};
|
|
300
|
-
$[
|
|
301
|
-
$[
|
|
303
|
+
$[39] = finalFocus;
|
|
304
|
+
$[40] = t19;
|
|
302
305
|
} else {
|
|
303
|
-
|
|
306
|
+
t19 = $[40];
|
|
304
307
|
}
|
|
305
|
-
let
|
|
306
|
-
if ($[
|
|
307
|
-
|
|
308
|
+
let t20;
|
|
309
|
+
if ($[41] === Symbol.for("react.memo_cache_sentinel")) {
|
|
310
|
+
t20 = /*#__PURE__*/_jsx(Icon, {
|
|
308
311
|
icon: Search,
|
|
309
312
|
size: 14,
|
|
310
313
|
className: "shrink-0 text-text-faint"
|
|
311
314
|
});
|
|
312
|
-
$[
|
|
315
|
+
$[41] = t20;
|
|
313
316
|
} else {
|
|
314
|
-
|
|
317
|
+
t20 = $[41];
|
|
315
318
|
}
|
|
316
|
-
let
|
|
317
|
-
if ($[
|
|
318
|
-
|
|
319
|
-
$[
|
|
320
|
-
$[
|
|
319
|
+
let t21;
|
|
320
|
+
if ($[42] !== t) {
|
|
321
|
+
t21 = t("pickers.model.search");
|
|
322
|
+
$[42] = t;
|
|
323
|
+
$[43] = t21;
|
|
321
324
|
} else {
|
|
322
|
-
|
|
325
|
+
t21 = $[43];
|
|
323
326
|
}
|
|
324
|
-
let
|
|
325
|
-
if ($[
|
|
326
|
-
|
|
327
|
+
let t22;
|
|
328
|
+
if ($[44] === Symbol.for("react.memo_cache_sentinel")) {
|
|
329
|
+
t22 = e_0 => {
|
|
327
330
|
setQuery(e_0.target.value);
|
|
328
331
|
setIndex(0);
|
|
329
332
|
};
|
|
330
|
-
$[
|
|
333
|
+
$[44] = t22;
|
|
331
334
|
} else {
|
|
332
|
-
|
|
335
|
+
t22 = $[44];
|
|
333
336
|
}
|
|
334
|
-
const
|
|
335
|
-
const
|
|
336
|
-
const
|
|
337
|
+
const t23 = "max-h-72 overflow-auto p-1";
|
|
338
|
+
const t24 = "listbox";
|
|
339
|
+
const t25 = entries.length === 0 && /*#__PURE__*/_jsx("div", {
|
|
337
340
|
className: "px-3 py-6 text-center text-xs text-text-faint",
|
|
338
341
|
children: providers.length === 0 ? t("pickers.model.noProvider") : t("pickers.model.noMatch")
|
|
339
342
|
});
|
|
340
|
-
const
|
|
343
|
+
const t26 = entries.map((entry_3, i_2) => {
|
|
341
344
|
if (entry_3.kind === "all") {
|
|
342
345
|
const before_0 = entries[i_2 - 1];
|
|
343
346
|
const header = grouped && (before_0 === undefined || before_0.kind === "legacy" || before_0.provider.kind !== entry_3.provider.kind);
|
|
@@ -452,51 +455,51 @@ export function ModelPicker(t0) {
|
|
|
452
455
|
})]
|
|
453
456
|
}, `${entry_3.provider.kind}/${entry_3.model.slug}`);
|
|
454
457
|
});
|
|
455
|
-
let
|
|
456
|
-
if ($[
|
|
457
|
-
|
|
458
|
+
let t27;
|
|
459
|
+
if ($[45] !== t25 || $[46] !== t26) {
|
|
460
|
+
t27 = /*#__PURE__*/_jsxs("div", {
|
|
458
461
|
ref: listRef,
|
|
459
|
-
className:
|
|
460
|
-
role:
|
|
461
|
-
children: [
|
|
462
|
+
className: t23,
|
|
463
|
+
role: t24,
|
|
464
|
+
children: [t25, t26]
|
|
462
465
|
});
|
|
463
|
-
$[44] = t24;
|
|
464
466
|
$[45] = t25;
|
|
465
467
|
$[46] = t26;
|
|
468
|
+
$[47] = t27;
|
|
466
469
|
} else {
|
|
467
|
-
|
|
470
|
+
t27 = $[47];
|
|
468
471
|
}
|
|
469
|
-
let
|
|
470
|
-
if ($[
|
|
471
|
-
|
|
472
|
+
let t28;
|
|
473
|
+
if ($[48] !== footer) {
|
|
474
|
+
t28 = footer !== undefined && /*#__PURE__*/_jsx("div", {
|
|
472
475
|
className: "border-t border-border-soft px-3 py-2 text-xs text-text-faint",
|
|
473
476
|
children: footer
|
|
474
477
|
});
|
|
475
|
-
$[
|
|
476
|
-
$[
|
|
478
|
+
$[48] = footer;
|
|
479
|
+
$[49] = t28;
|
|
477
480
|
} else {
|
|
478
|
-
|
|
481
|
+
t28 = $[49];
|
|
479
482
|
}
|
|
480
483
|
return /*#__PURE__*/_jsxs(Popover.Root, {
|
|
481
484
|
open: open,
|
|
482
485
|
onOpenChange: setOpen,
|
|
483
|
-
children: [
|
|
486
|
+
children: [t18, /*#__PURE__*/_jsxs(Popover.Popup, {
|
|
484
487
|
variant: "picker",
|
|
485
488
|
side: side,
|
|
486
489
|
initialFocus: inputRef,
|
|
487
|
-
...
|
|
490
|
+
...t19,
|
|
488
491
|
children: [/*#__PURE__*/_jsxs("div", {
|
|
489
492
|
className: "flex items-center gap-2 border-b border-border px-2.5",
|
|
490
|
-
children: [
|
|
493
|
+
children: [t20, /*#__PURE__*/_jsx("input", {
|
|
491
494
|
ref: inputRef,
|
|
492
495
|
className: "h-8 w-full bg-transparent text-sm text-text outline-none placeholder:text-text-faint",
|
|
493
|
-
placeholder:
|
|
496
|
+
placeholder: t21,
|
|
494
497
|
spellCheck: false,
|
|
495
498
|
value: query,
|
|
496
|
-
onChange:
|
|
499
|
+
onChange: t22,
|
|
497
500
|
onKeyDown: onKeyDown
|
|
498
501
|
})]
|
|
499
|
-
}),
|
|
502
|
+
}), t27, t28]
|
|
500
503
|
})]
|
|
501
504
|
});
|
|
502
505
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ChatSkill } from '@adecore/agent-contracts';
|
|
2
|
+
import type { Referables } from '../chat-references.js';
|
|
3
|
+
import { type PromptDraft } from './composer/use-prompt-menus.js';
|
|
4
|
+
interface PromptEditorProps {
|
|
5
|
+
value: PromptDraft;
|
|
6
|
+
onChange(next: PromptDraft): void;
|
|
7
|
+
label: string;
|
|
8
|
+
placeholder: string;
|
|
9
|
+
skills: readonly ChatSkill[];
|
|
10
|
+
slashCommands?: readonly string[];
|
|
11
|
+
goals?: boolean;
|
|
12
|
+
cwd: string | null;
|
|
13
|
+
referables: Referables;
|
|
14
|
+
providerName?: string;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function PromptEditor({ value, onChange, label, placeholder, skills, slashCommands, goals, cwd, referables, providerName, disabled, className }: PromptEditorProps): import("react").JSX.Element;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef } from 'react';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import { Surface } from '@adecore/ui';
|
|
4
|
+
import { ComposerInput } from './ComposerInput.js';
|
|
5
|
+
import { chipDecorations } from './composer/chips.js';
|
|
6
|
+
import { ComposerMenu } from './composer/ComposerMenu.js';
|
|
7
|
+
import { pickInMenu } from './composer/key-handler.js';
|
|
8
|
+
import { usePromptMenus } from './composer/use-prompt-menus.js';
|
|
9
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
|
+
const NO_COMMANDS = [];
|
|
11
|
+
/*
|
|
12
|
+
* A prompt written now and sent later, as a form field: the composer's editor with its pickers and chips,
|
|
13
|
+
* without a chat behind it. The host hands in what the CLI it goes to has, and keeps what was picked.
|
|
14
|
+
*/
|
|
15
|
+
export function PromptEditor({
|
|
16
|
+
value,
|
|
17
|
+
onChange,
|
|
18
|
+
label,
|
|
19
|
+
placeholder,
|
|
20
|
+
skills,
|
|
21
|
+
slashCommands = NO_COMMANDS,
|
|
22
|
+
goals = false,
|
|
23
|
+
cwd,
|
|
24
|
+
referables,
|
|
25
|
+
providerName,
|
|
26
|
+
disabled = false,
|
|
27
|
+
className
|
|
28
|
+
}) {
|
|
29
|
+
const inputRef = useRef(null);
|
|
30
|
+
// A pick writes twice in one event (the text, then what it picked), and the second must build on the first.
|
|
31
|
+
const latest = useRef(value);
|
|
32
|
+
useLayoutEffect(() => {
|
|
33
|
+
latest.current = value;
|
|
34
|
+
}, [value]);
|
|
35
|
+
const setDraft = action => {
|
|
36
|
+
const next = typeof action === 'function' ? action(latest.current) : action;
|
|
37
|
+
latest.current = next;
|
|
38
|
+
onChange(next);
|
|
39
|
+
};
|
|
40
|
+
const setText = (next_0, mentions = value.mentions, chosen = value.skills) => {
|
|
41
|
+
setDraft(current => ({
|
|
42
|
+
...current,
|
|
43
|
+
text: next_0,
|
|
44
|
+
mentions,
|
|
45
|
+
skills: chosen
|
|
46
|
+
}));
|
|
47
|
+
};
|
|
48
|
+
const menus = usePromptMenus({
|
|
49
|
+
draft: {
|
|
50
|
+
draft: value,
|
|
51
|
+
setDraft,
|
|
52
|
+
setText
|
|
53
|
+
},
|
|
54
|
+
inputRef,
|
|
55
|
+
cwd,
|
|
56
|
+
skills,
|
|
57
|
+
slashCommands,
|
|
58
|
+
goals,
|
|
59
|
+
providerName,
|
|
60
|
+
referables,
|
|
61
|
+
label
|
|
62
|
+
});
|
|
63
|
+
const extensions = chipDecorations({
|
|
64
|
+
mentions: value.mentions,
|
|
65
|
+
skills: value.skills,
|
|
66
|
+
references: menus.referenceChips
|
|
67
|
+
});
|
|
68
|
+
const onKeyDown = e => {
|
|
69
|
+
if (e.isComposing) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
// Escape closes the picker, and only that: the dialog around the field stays.
|
|
73
|
+
if (e.key === 'Escape' && menus.menuOpen) {
|
|
74
|
+
menus.close();
|
|
75
|
+
e.stopPropagation();
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
// Enter adds a line here rather than sending, so on a command it completes like Tab.
|
|
79
|
+
if (e.key === 'Enter' && menus.commandMenuOpen) {
|
|
80
|
+
menus.completeCommand(menus.commands[menus.activeIndex]);
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
return pickInMenu(e, menus);
|
|
84
|
+
};
|
|
85
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
86
|
+
className: clsx('relative', className),
|
|
87
|
+
children: [menus.menuOpen && /*#__PURE__*/_jsx(Surface, {
|
|
88
|
+
className: "absolute inset-x-0 top-full z-50 mt-1 overflow-hidden rounded-lg bg-clip-padding *:border-b-0",
|
|
89
|
+
children: /*#__PURE__*/_jsx(ComposerMenu, {
|
|
90
|
+
menus: menus
|
|
91
|
+
})
|
|
92
|
+
}), /*#__PURE__*/_jsx("div", {
|
|
93
|
+
className: "field h-auto overflow-hidden p-0 focus-ring-within",
|
|
94
|
+
children: /*#__PURE__*/_jsx(ComposerInput, {
|
|
95
|
+
ref: inputRef,
|
|
96
|
+
dictationToolbar: null,
|
|
97
|
+
className: "composer-input prompt-editor select-text text-sm leading-normal text-text",
|
|
98
|
+
value: value.text,
|
|
99
|
+
placeholder: placeholder,
|
|
100
|
+
disabled: disabled,
|
|
101
|
+
tabbable: true,
|
|
102
|
+
extensions: extensions,
|
|
103
|
+
aria: menus.inputAria,
|
|
104
|
+
onChange: (text, selection, state) => {
|
|
105
|
+
setText(text);
|
|
106
|
+
menus.setMenuIndex(0);
|
|
107
|
+
menus.trackTriggers(text, selection, state);
|
|
108
|
+
},
|
|
109
|
+
onSelectionChange: menus.trackTriggers,
|
|
110
|
+
onBlur: menus.close,
|
|
111
|
+
onKeyDown: onKeyDown
|
|
112
|
+
})
|
|
113
|
+
})]
|
|
114
|
+
});
|
|
115
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
-
export declare function Timeline({ chatId, composer, overlay }: {
|
|
2
|
+
export declare function Timeline({ chatId, composer, overlay, onContentHeight }: {
|
|
3
3
|
chatId: string;
|
|
4
4
|
composer?: ReactNode;
|
|
5
5
|
overlay?: ReactNode;
|
|
6
|
+
onContentHeight?: (height: number) => void;
|
|
6
7
|
}): import("react").JSX.Element;
|
package/dist/chat/ui/Timeline.js
CHANGED
|
@@ -388,11 +388,15 @@ const ThreadRow = memo(function ThreadRow(t0) {
|
|
|
388
388
|
/*
|
|
389
389
|
* `overlay` stands in the thread's place and ends where the composer starts, so the thread keeps
|
|
390
390
|
* where it was underneath and the composer stays in reach for the prompts it answers.
|
|
391
|
+
* `onContentHeight` hears what the thread's rows and its padding take, without the composer, once
|
|
392
|
+
* the rows in view are laid out at their real heights, for a host that sizes its frame to the thread.
|
|
393
|
+
* Rows out of view still count at an estimate, so a frame up to the viewport's height gets it exact.
|
|
391
394
|
*/
|
|
392
395
|
export function Timeline({
|
|
393
396
|
chatId,
|
|
394
397
|
composer,
|
|
395
|
-
overlay
|
|
398
|
+
overlay,
|
|
399
|
+
onContentHeight
|
|
396
400
|
}) {
|
|
397
401
|
const host = useChatHost();
|
|
398
402
|
const {
|
|
@@ -605,6 +609,14 @@ export function Timeline({
|
|
|
605
609
|
setMeasuredThread(keyOf(chatId));
|
|
606
610
|
}
|
|
607
611
|
}, [initialLayout, empty, loadingHistory, frame.height, virtualRows, virtualizer, rows.length, keyOf, chatId]);
|
|
612
|
+
useLayoutEffect(() => {
|
|
613
|
+
const thread = threadRef.current;
|
|
614
|
+
if (onContentHeight === undefined || initialLayout || empty || loadingHistory || thread === null) {
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
const style = getComputedStyle(thread);
|
|
618
|
+
onContentHeight(totalSize + (Number.parseFloat(style.paddingTop) || 0) + (Number.parseFloat(style.paddingBottom) || 0));
|
|
619
|
+
}, [onContentHeight, initialLayout, empty, loadingHistory, totalSize]);
|
|
608
620
|
useLayoutEffect(() => {
|
|
609
621
|
const element_2 = scrollRef.current;
|
|
610
622
|
if (!followRef.current || element_2 === null) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Ref } from 'react';
|
|
2
2
|
import type { ChatInfo } from '@adecore/agent-contracts';
|
|
3
3
|
import { type Shortcut } from '@adecore/ui';
|
|
4
|
+
import { type ComposerSendAction, type ComposerSendDraft } from '../../../host.js';
|
|
4
5
|
import type { StashedPrompt } from '../../stash.js';
|
|
5
6
|
import type { ChatControls } from './use-chat-controls.js';
|
|
6
7
|
interface SendProps {
|
|
@@ -10,6 +11,8 @@ interface SendProps {
|
|
|
10
11
|
kbd: Shortcut;
|
|
11
12
|
onSend(alternate: boolean): void;
|
|
12
13
|
onContinue: (() => void) | null;
|
|
14
|
+
actions: readonly ComposerSendAction[];
|
|
15
|
+
draft: ComposerSendDraft;
|
|
13
16
|
}
|
|
14
17
|
interface ComposerControlsProps {
|
|
15
18
|
chatId: string;
|