@adecore/agents-react 0.37.3 → 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.
Files changed (66) hide show
  1. package/dist/agents/AgentModelLabel.d.ts +10 -0
  2. package/dist/agents/AgentModelLabel.js +97 -0
  3. package/dist/chat/logic/visual-height.d.ts +1 -0
  4. package/dist/chat/logic/visual-height.js +1 -1
  5. package/dist/chat/ui/Composer.js +385 -360
  6. package/dist/chat/ui/HostMenuItems.d.ts +4 -0
  7. package/dist/chat/ui/HostMenuItems.js +15 -0
  8. package/dist/chat/ui/Pickers.d.ts +2 -1
  9. package/dist/chat/ui/Pickers.js +126 -123
  10. package/dist/chat/ui/PromptEditor.d.ts +19 -0
  11. package/dist/chat/ui/PromptEditor.js +115 -0
  12. package/dist/chat/ui/Timeline.d.ts +2 -1
  13. package/dist/chat/ui/Timeline.js +13 -1
  14. package/dist/chat/ui/VisualFrame.d.ts +8 -0
  15. package/dist/chat/ui/VisualFrame.js +217 -115
  16. package/dist/chat/ui/composer/ComposerControls.d.ts +3 -0
  17. package/dist/chat/ui/composer/ComposerControls.js +235 -38
  18. package/dist/chat/ui/composer/key-handler.d.ts +1 -1
  19. package/dist/chat/ui/composer/key-handler.js +3 -11
  20. package/dist/chat/ui/composer/prompt-picks.d.ts +4 -0
  21. package/dist/chat/ui/composer/prompt-picks.js +14 -0
  22. package/dist/chat/ui/composer/use-composer-menus.d.ts +4 -49
  23. package/dist/chat/ui/composer/use-composer-menus.js +65 -519
  24. package/dist/chat/ui/composer/use-prompt-menus.d.ts +73 -0
  25. package/dist/chat/ui/composer/use-prompt-menus.js +536 -0
  26. package/dist/chat/ui/index.d.ts +4 -0
  27. package/dist/chat/ui/index.js +3 -0
  28. package/dist/chat/ui/rows/GeneratedImageRow.js +8 -4
  29. package/dist/chat/ui/rows/VisualRow.js +184 -142
  30. package/dist/chat/ui/rows/row-rhythm.js +6 -4
  31. package/dist/host-hooks.d.ts +2 -1
  32. package/dist/host-hooks.js +6 -0
  33. package/dist/host.d.ts +27 -1
  34. package/dist/index.d.ts +1 -1
  35. package/dist/locales/en/agent-chat.d.ts +1 -0
  36. package/dist/locales/en/agent-chat.js +1 -0
  37. package/dist/locales/nl/agent-chat.d.ts +1 -0
  38. package/dist/locales/nl/agent-chat.js +1 -0
  39. package/dist/providers/index.d.ts +1 -0
  40. package/dist/providers/index.js +1 -0
  41. package/dist/theme.css +3 -0
  42. package/package.json +8 -8
  43. package/src/agents/AgentModelLabel.tsx +40 -0
  44. package/src/chat/logic/visual-height.ts +1 -1
  45. package/src/chat/ui/Composer.tsx +12 -3
  46. package/src/chat/ui/HostMenuItems.tsx +11 -0
  47. package/src/chat/ui/Pickers.tsx +4 -1
  48. package/src/chat/ui/PromptEditor.tsx +130 -0
  49. package/src/chat/ui/Timeline.tsx +22 -1
  50. package/src/chat/ui/VisualFrame.tsx +68 -21
  51. package/src/chat/ui/composer/ComposerControls.tsx +65 -15
  52. package/src/chat/ui/composer/key-handler.ts +3 -9
  53. package/src/chat/ui/composer/prompt-picks.ts +17 -0
  54. package/src/chat/ui/composer/use-composer-menus.ts +18 -275
  55. package/src/chat/ui/composer/use-prompt-menus.ts +341 -0
  56. package/src/chat/ui/index.ts +4 -0
  57. package/src/chat/ui/rows/GeneratedImageRow.tsx +9 -4
  58. package/src/chat/ui/rows/VisualRow.tsx +5 -1
  59. package/src/chat/ui/rows/row-rhythm.ts +6 -4
  60. package/src/host-hooks.ts +9 -1
  61. package/src/host.ts +45 -1
  62. package/src/index.ts +3 -0
  63. package/src/locales/en/agent-chat.ts +1 -0
  64. package/src/locales/nl/agent-chat.ts +1 -0
  65. package/src/providers/index.ts +1 -0
  66. package/src/theme.css +3 -0
@@ -5,6 +5,7 @@ import { ButtonGroup, ErrorBoundary, Icon, IconButton, Menu, Surface } from '@ad
5
5
  import { useChatHost } from '../../../host.js';
6
6
  import { useChatScope } from '../../../scope.js';
7
7
  import { useVisualDialog } from '../../visuals.js';
8
+ import { HostMenuItems } from '../HostMenuItems.js';
8
9
  import { VisualFrame } from '../VisualFrame.js';
9
10
  /*
10
11
  * A page an agent published, borderless on the thread's ground, with its width set by the row. Its few
@@ -14,7 +15,7 @@ import { VisualFrame } from '../VisualFrame.js';
14
15
  */
15
16
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
17
  export function VisualRow(t0) {
17
- const $ = _c(50);
18
+ const $ = _c(63);
18
19
  const {
19
20
  chatId,
20
21
  visual
@@ -24,223 +25,264 @@ export function VisualRow(t0) {
24
25
  t
25
26
  } = useTranslation("agent-chat");
26
27
  const {
28
+ id: scopeId,
27
29
  keyOf
28
30
  } = useChatScope();
29
31
  if (host.visuals === null) {
30
32
  return null;
31
33
  }
32
34
  let t1;
33
- if ($[0] !== chatId || $[1] !== keyOf || $[2] !== visual.id) {
34
- t1 = kind => useVisualDialog.getState().open(keyOf(chatId), visual.id, kind);
35
+ if ($[0] !== chatId || $[1] !== host.visuals || $[2] !== scopeId || $[3] !== visual) {
36
+ t1 = host.visuals.actions?.(scopeId, chatId, visual) ?? [];
35
37
  $[0] = chatId;
36
- $[1] = keyOf;
37
- $[2] = visual.id;
38
- $[3] = t1;
38
+ $[1] = host.visuals;
39
+ $[2] = scopeId;
40
+ $[3] = visual;
41
+ $[4] = t1;
39
42
  } else {
40
- t1 = $[3];
43
+ t1 = $[4];
41
44
  }
42
- const open = t1;
45
+ const extra = t1;
43
46
  let t2;
44
- if ($[4] !== t) {
45
- t2 = t("visuals.renderFailed");
46
- $[4] = t;
47
- $[5] = t2;
47
+ if ($[5] !== chatId || $[6] !== keyOf || $[7] !== visual.id) {
48
+ t2 = kind => useVisualDialog.getState().open(keyOf(chatId), visual.id, kind);
49
+ $[5] = chatId;
50
+ $[6] = keyOf;
51
+ $[7] = visual.id;
52
+ $[8] = t2;
48
53
  } else {
49
- t2 = $[5];
54
+ t2 = $[8];
50
55
  }
56
+ const open = t2;
51
57
  let t3;
52
- if ($[6] !== visual) {
53
- t3 = [visual];
54
- $[6] = visual;
55
- $[7] = t3;
58
+ if ($[9] !== t) {
59
+ t3 = t("visuals.renderFailed");
60
+ $[9] = t;
61
+ $[10] = t3;
56
62
  } else {
57
- t3 = $[7];
63
+ t3 = $[10];
58
64
  }
59
65
  let t4;
60
- if ($[8] !== chatId || $[9] !== visual) {
61
- t4 = /*#__PURE__*/_jsx(VisualFrame, {
62
- chatId: chatId,
63
- visual: visual
64
- });
65
- $[8] = chatId;
66
- $[9] = visual;
67
- $[10] = t4;
66
+ if ($[11] !== visual) {
67
+ t4 = [visual];
68
+ $[11] = visual;
69
+ $[12] = t4;
68
70
  } else {
69
- t4 = $[10];
71
+ t4 = $[12];
70
72
  }
71
73
  let t5;
72
- if ($[11] !== t || $[12] !== visual.title) {
73
- t5 = t("visuals.actions", {
74
- title: visual.title
74
+ if ($[13] !== chatId || $[14] !== visual) {
75
+ t5 = /*#__PURE__*/_jsx(VisualFrame, {
76
+ chatId: chatId,
77
+ visual: visual
75
78
  });
76
- $[11] = t;
77
- $[12] = visual.title;
78
- $[13] = t5;
79
+ $[13] = chatId;
80
+ $[14] = visual;
81
+ $[15] = t5;
79
82
  } else {
80
- t5 = $[13];
83
+ t5 = $[15];
81
84
  }
82
85
  let t6;
83
- if ($[14] !== t) {
84
- t6 = t("visuals.expand");
85
- $[14] = t;
86
- $[15] = t6;
86
+ if ($[16] !== t || $[17] !== visual.title) {
87
+ t6 = t("visuals.actions", {
88
+ title: visual.title
89
+ });
90
+ $[16] = t;
91
+ $[17] = visual.title;
92
+ $[18] = t6;
87
93
  } else {
88
- t6 = $[15];
94
+ t6 = $[18];
89
95
  }
90
96
  let t7;
91
- if ($[16] !== open) {
92
- t7 = () => open("expand");
93
- $[16] = open;
94
- $[17] = t7;
97
+ if ($[19] !== t) {
98
+ t7 = t("visuals.expand");
99
+ $[19] = t;
100
+ $[20] = t7;
95
101
  } else {
96
- t7 = $[17];
102
+ t7 = $[20];
97
103
  }
98
104
  let t8;
99
- if ($[18] !== t6 || $[19] !== t7) {
100
- t8 = /*#__PURE__*/_jsx(IconButton, {
101
- icon: Maximize2,
102
- size: "sm",
103
- label: t6,
104
- onClick: t7
105
- });
106
- $[18] = t6;
107
- $[19] = t7;
108
- $[20] = t8;
105
+ if ($[21] !== open) {
106
+ t8 = () => open("expand");
107
+ $[21] = open;
108
+ $[22] = t8;
109
109
  } else {
110
- t8 = $[20];
110
+ t8 = $[22];
111
111
  }
112
112
  let t9;
113
- if ($[21] !== t) {
114
- t9 = t("visuals.more");
115
- $[21] = t;
116
- $[22] = t9;
113
+ if ($[23] !== t7 || $[24] !== t8) {
114
+ t9 = /*#__PURE__*/_jsx(IconButton, {
115
+ icon: Maximize2,
116
+ size: "sm",
117
+ label: t7,
118
+ onClick: t8
119
+ });
120
+ $[23] = t7;
121
+ $[24] = t8;
122
+ $[25] = t9;
117
123
  } else {
118
- t9 = $[22];
124
+ t9 = $[25];
119
125
  }
120
126
  let t10;
121
- if ($[23] === Symbol.for("react.memo_cache_sentinel")) {
122
- t10 = /*#__PURE__*/_jsx(Menu.Trigger, {});
123
- $[23] = t10;
127
+ if ($[26] !== t) {
128
+ t10 = t("visuals.more");
129
+ $[26] = t;
130
+ $[27] = t10;
124
131
  } else {
125
- t10 = $[23];
132
+ t10 = $[27];
126
133
  }
127
134
  let t11;
128
- if ($[24] !== t9) {
129
- t11 = /*#__PURE__*/_jsx(IconButton, {
130
- icon: Ellipsis,
131
- size: "sm",
132
- label: t9,
133
- render: t10
134
- });
135
- $[24] = t9;
136
- $[25] = t11;
135
+ if ($[28] === Symbol.for("react.memo_cache_sentinel")) {
136
+ t11 = /*#__PURE__*/_jsx(Menu.Trigger, {});
137
+ $[28] = t11;
137
138
  } else {
138
- t11 = $[25];
139
+ t11 = $[28];
139
140
  }
140
141
  let t12;
141
- if ($[26] !== open) {
142
- t12 = () => open("remove");
143
- $[26] = open;
144
- $[27] = t12;
142
+ if ($[29] !== t10) {
143
+ t12 = /*#__PURE__*/_jsx(IconButton, {
144
+ icon: Ellipsis,
145
+ size: "sm",
146
+ label: t10,
147
+ render: t11
148
+ });
149
+ $[29] = t10;
150
+ $[30] = t12;
145
151
  } else {
146
- t12 = $[27];
152
+ t12 = $[30];
147
153
  }
148
154
  let t13;
149
- if ($[28] === Symbol.for("react.memo_cache_sentinel")) {
150
- t13 = /*#__PURE__*/_jsx(Icon, {
151
- icon: Trash2,
152
- size: 14
155
+ if ($[31] !== extra) {
156
+ t13 = /*#__PURE__*/_jsx(HostMenuItems, {
157
+ actions: extra
153
158
  });
154
- $[28] = t13;
159
+ $[31] = extra;
160
+ $[32] = t13;
155
161
  } else {
156
- t13 = $[28];
162
+ t13 = $[32];
157
163
  }
158
164
  let t14;
159
- if ($[29] !== t) {
160
- t14 = t("visuals.remove");
161
- $[29] = t;
162
- $[30] = t14;
165
+ if ($[33] !== extra.length) {
166
+ t14 = extra.length > 0 && /*#__PURE__*/_jsx(Menu.Separator, {});
167
+ $[33] = extra.length;
168
+ $[34] = t14;
163
169
  } else {
164
- t14 = $[30];
170
+ t14 = $[34];
165
171
  }
166
172
  let t15;
167
- if ($[31] !== t12 || $[32] !== t14) {
168
- t15 = /*#__PURE__*/_jsx(Menu.Popup, {
169
- align: "end",
170
- children: /*#__PURE__*/_jsxs(Menu.Item, {
171
- onClick: t12,
172
- children: [t13, " ", t14]
173
- })
174
- });
175
- $[31] = t12;
176
- $[32] = t14;
177
- $[33] = t15;
173
+ if ($[35] !== open) {
174
+ t15 = () => open("remove");
175
+ $[35] = open;
176
+ $[36] = t15;
178
177
  } else {
179
- t15 = $[33];
178
+ t15 = $[36];
180
179
  }
181
180
  let t16;
182
- if ($[34] !== t11 || $[35] !== t15) {
183
- t16 = /*#__PURE__*/_jsxs(Menu.Root, {
184
- children: [t11, t15]
181
+ if ($[37] === Symbol.for("react.memo_cache_sentinel")) {
182
+ t16 = /*#__PURE__*/_jsx(Icon, {
183
+ icon: Trash2,
184
+ size: 14
185
185
  });
186
- $[34] = t11;
187
- $[35] = t15;
188
- $[36] = t16;
186
+ $[37] = t16;
189
187
  } else {
190
- t16 = $[36];
188
+ t16 = $[37];
191
189
  }
192
190
  let t17;
193
- if ($[37] !== t16 || $[38] !== t8) {
194
- t17 = /*#__PURE__*/_jsxs(ButtonGroup, {
195
- children: [t8, t16]
196
- });
197
- $[37] = t16;
198
- $[38] = t8;
191
+ if ($[38] !== t) {
192
+ t17 = t("visuals.remove");
193
+ $[38] = t;
199
194
  $[39] = t17;
200
195
  } else {
201
196
  t17 = $[39];
202
197
  }
203
198
  let t18;
204
- if ($[40] !== t17 || $[41] !== t5) {
205
- t18 = /*#__PURE__*/_jsx(Surface, {
206
- role: "toolbar",
207
- "aria-label": t5,
208
- className: "absolute top-2 right-2 rounded-lg p-0.5 opacity-0 transition-opacity group-focus-within/visual:opacity-100 group-hover/visual:opacity-100 has-[[data-popup-open]]:opacity-100 pointer-coarse:opacity-100",
209
- children: t17
199
+ if ($[40] !== t15 || $[41] !== t17) {
200
+ t18 = /*#__PURE__*/_jsxs(Menu.Item, {
201
+ onClick: t15,
202
+ children: [t16, " ", t17]
210
203
  });
211
- $[40] = t17;
212
- $[41] = t5;
204
+ $[40] = t15;
205
+ $[41] = t17;
213
206
  $[42] = t18;
214
207
  } else {
215
208
  t18 = $[42];
216
209
  }
217
210
  let t19;
218
- if ($[43] !== t18 || $[44] !== t4) {
219
- t19 = /*#__PURE__*/_jsxs("div", {
220
- className: "group/visual relative",
221
- children: [t4, t18]
211
+ if ($[43] !== t13 || $[44] !== t14 || $[45] !== t18) {
212
+ t19 = /*#__PURE__*/_jsxs(Menu.Popup, {
213
+ align: "end",
214
+ children: [t13, t14, t18]
222
215
  });
223
- $[43] = t18;
224
- $[44] = t4;
225
- $[45] = t19;
216
+ $[43] = t13;
217
+ $[44] = t14;
218
+ $[45] = t18;
219
+ $[46] = t19;
226
220
  } else {
227
- t19 = $[45];
221
+ t19 = $[46];
228
222
  }
229
223
  let t20;
230
- if ($[46] !== t19 || $[47] !== t2 || $[48] !== t3) {
231
- t20 = /*#__PURE__*/_jsx(ErrorBoundary, {
232
- label: t2,
233
- resetKeys: t3,
234
- compact: true,
235
- className: "relative rounded-lg",
236
- children: t19
224
+ if ($[47] !== t12 || $[48] !== t19) {
225
+ t20 = /*#__PURE__*/_jsxs(Menu.Root, {
226
+ children: [t12, t19]
237
227
  });
238
- $[46] = t19;
239
- $[47] = t2;
240
- $[48] = t3;
228
+ $[47] = t12;
229
+ $[48] = t19;
241
230
  $[49] = t20;
242
231
  } else {
243
232
  t20 = $[49];
244
233
  }
245
- return t20;
234
+ let t21;
235
+ if ($[50] !== t20 || $[51] !== t9) {
236
+ t21 = /*#__PURE__*/_jsxs(ButtonGroup, {
237
+ children: [t9, t20]
238
+ });
239
+ $[50] = t20;
240
+ $[51] = t9;
241
+ $[52] = t21;
242
+ } else {
243
+ t21 = $[52];
244
+ }
245
+ let t22;
246
+ if ($[53] !== t21 || $[54] !== t6) {
247
+ t22 = /*#__PURE__*/_jsx(Surface, {
248
+ role: "toolbar",
249
+ "aria-label": t6,
250
+ className: "absolute top-2 right-2 rounded-lg p-0.5 opacity-0 transition-opacity group-focus-within/visual:opacity-100 group-hover/visual:opacity-100 has-[[data-popup-open]]:opacity-100 pointer-coarse:opacity-100",
251
+ children: t21
252
+ });
253
+ $[53] = t21;
254
+ $[54] = t6;
255
+ $[55] = t22;
256
+ } else {
257
+ t22 = $[55];
258
+ }
259
+ let t23;
260
+ if ($[56] !== t22 || $[57] !== t5) {
261
+ t23 = /*#__PURE__*/_jsxs("div", {
262
+ className: "group/visual relative",
263
+ children: [t5, t22]
264
+ });
265
+ $[56] = t22;
266
+ $[57] = t5;
267
+ $[58] = t23;
268
+ } else {
269
+ t23 = $[58];
270
+ }
271
+ let t24;
272
+ if ($[59] !== t23 || $[60] !== t3 || $[61] !== t4) {
273
+ t24 = /*#__PURE__*/_jsx(ErrorBoundary, {
274
+ label: t3,
275
+ resetKeys: t4,
276
+ compact: true,
277
+ className: "relative rounded-lg",
278
+ children: t23
279
+ });
280
+ $[59] = t23;
281
+ $[60] = t3;
282
+ $[61] = t4;
283
+ $[62] = t24;
284
+ } else {
285
+ t24 = $[62];
286
+ }
287
+ return t24;
246
288
  }
@@ -4,13 +4,15 @@ import { isBlock } from '../../logic/timeline.js';
4
4
  export const FOLLOW_THRESHOLD_PX = 40;
5
5
  /*
6
6
  * The gaps a row wears for where it sits: a question is followed by its answer gap, and a seam where
7
- * the list rhythm of tool lines meets the block rhythm of prose gets the block gap. A visual has no
8
- * margin of its own like prose does, so the row under one takes the block gap too. A question
9
- * already carries the gap before it, and the row after one is the answer, so neither takes a seam.
7
+ * the list rhythm of tool lines meets the block rhythm of prose gets the block gap. A visual and an
8
+ * app's card have no margin of their own like prose does, so the row under one takes the block gap
9
+ * too. A question already carries the gap before it, and the row after one is the answer, so neither
10
+ * takes a seam.
10
11
  */
11
12
  export function rowRhythm(row, previous) {
12
13
  const question = row.kind === 'user';
13
- const seam = !question && previous !== null && previous.kind !== 'user' && (isBlock(row) !== isBlock(previous) || previous.kind === 'visual');
14
+ const bare = previous?.kind === 'visual' || previous?.kind === 'app-card';
15
+ const seam = !question && previous !== null && previous.kind !== 'user' && (isBlock(row) !== isBlock(previous) || bare);
14
16
  return clsx(question && 'pb-(--chat-answer-gap)', seam && 'pt-(--chat-block-gap)');
15
17
  }
16
18
  /*
@@ -1,6 +1,6 @@
1
1
  import type { ProviderPlatform } from '@adecore/agent-contracts';
2
2
  import { type Referables } from './chat/chat-references.js';
3
- import { type ChatHost, type CommandLook } from './host.js';
3
+ import { type ChatHost, type CommandLook, type ComposerSendAction } from './host.js';
4
4
  export declare function useHostCodeMode(): 'light' | 'dark';
5
5
  export declare function useHostCodeThemes(): {
6
6
  light: string;
@@ -25,6 +25,7 @@ export declare function useHostHidesFolder(...args: Parameters<ChatHost['useHide
25
25
  export declare function useHostWelcome(...args: Parameters<ChatHost['useWelcome']>): ReturnType<ChatHost['useWelcome']>;
26
26
  export declare function useHostResumeAtReset(...args: Parameters<ChatHost['useResumeAtReset']>): ReturnType<ChatHost['useResumeAtReset']>;
27
27
  export declare function useHostComposerPlaceholder(...args: Parameters<ChatHost['useComposerPlaceholder']>): ReturnType<ChatHost['useComposerPlaceholder']>;
28
+ export declare function useHostComposerSendActions(scopeId: string, chatId: string): readonly ComposerSendAction[];
28
29
  export declare function useHostThreadCards(...args: Parameters<ChatHost['useThreadCards']>): ReturnType<ChatHost['useThreadCards']>;
29
30
  export declare function useHostReplyAuthor(...args: Parameters<ChatHost['useReplyAuthor']>): ReturnType<ChatHost['useReplyAuthor']>;
30
31
  export declare function useHostMapSource(maps: NonNullable<ChatHost['maps']>, scopeId: string): ReturnType<NonNullable<ChatHost['maps']>['useSource']>;
@@ -71,6 +71,12 @@ export function useHostResumeAtReset(...args) {
71
71
  export function useHostComposerPlaceholder(...args) {
72
72
  return useChatHost().useComposerPlaceholder(...args);
73
73
  }
74
+ const NO_SEND_ACTIONS = [];
75
+ const noSendActions = () => NO_SEND_ACTIONS;
76
+ export function useHostComposerSendActions(scopeId, chatId) {
77
+ const useSendActions = useChatHost().useComposerSendActions ?? noSendActions;
78
+ return useSendActions(scopeId, chatId);
79
+ }
74
80
  export function useHostThreadCards(...args) {
75
81
  return useChatHost().useThreadCards(...args);
76
82
  }
package/dist/host.d.ts CHANGED
@@ -2,8 +2,9 @@ import { type ComponentProps, type ComponentType, type ReactNode, type RefObject
2
2
  import type { Extension } from '@codemirror/state';
3
3
  import type { EditorView } from '@codemirror/view';
4
4
  import type { Highlighter, ThemeRegistration } from 'shiki';
5
+ import type { LucideIcon } from 'lucide-react';
5
6
  import type { EditorEngine } from '@adecore/editor';
6
- import type { AgentKind, ChatCheckpointDiff, ChatConfigurePayload, ChatGoalAction, ChatItem, ChatSubagentItem, ChatUiChoicePayload, ChatUiQueryPayload, ChatUiQueryReading, ChatUiLinkPayload, ChatUiLinkReading, ProviderPlatform } from '@adecore/agent-contracts';
7
+ import type { AgentKind, ChatAttachment, ChatCheckpointDiff, ChatConfigurePayload, ChatGoalAction, ChatItem, ChatSubagentItem, ChatUiChoicePayload, ChatUiQueryPayload, ChatUiQueryReading, ChatUiLinkPayload, ChatUiLinkReading, ChatVisual, ModelSelection, ProviderPlatform, RuntimeMode } from '@adecore/agent-contracts';
7
8
  import type { Referables } from './chat/chat-references.js';
8
9
  import type { TimelineRow } from './chat/logic/timeline.js';
9
10
  import type { FindReveal } from './chat/ui/find-reveal.js';
@@ -109,6 +110,21 @@ export interface ComposerSlotProps {
109
110
  disabled: boolean;
110
111
  insert(text: string): void;
111
112
  }
113
+ export interface ComposerSendDraft {
114
+ scopeId: string;
115
+ chatId: string;
116
+ text: string;
117
+ provider: AgentKind;
118
+ selection: ModelSelection;
119
+ runtimeMode: RuntimeMode;
120
+ }
121
+ export interface ComposerSendAction {
122
+ id: string;
123
+ label: string;
124
+ icon?: LucideIcon;
125
+ disabled?: boolean;
126
+ run(draft: ComposerSendDraft): void;
127
+ }
112
128
  export interface SubagentSlotProps {
113
129
  chatId: string;
114
130
  items: readonly ChatSubagentItem[];
@@ -121,6 +137,14 @@ export interface ThreadCard {
121
137
  export interface VisualHost {
122
138
  frameUrl: string;
123
139
  openLink(url: string): void;
140
+ actions?(scopeId: string, chatId: string, visual: ChatVisual): readonly HostMenuAction[];
141
+ }
142
+ export interface HostMenuAction {
143
+ id: string;
144
+ label: string;
145
+ icon?: LucideIcon;
146
+ disabled?: boolean;
147
+ run(): void;
124
148
  }
125
149
  export interface ReplyAuthor {
126
150
  name: string;
@@ -201,6 +225,7 @@ export interface ChatHost {
201
225
  read(scopeId: string, chatId: string, attachmentId: string): Promise<Blob>;
202
226
  open?(scopeId: string, chatId: string, attachmentId: string, suggestedName: string): void;
203
227
  saveToProject?(scopeId: string, chatId: string, attachmentId: string, suggestedName: string): Promise<string | null>;
228
+ actions?(scopeId: string, chatId: string, attachment: ChatAttachment): readonly HostMenuAction[];
204
229
  };
205
230
  ReadImage: ComponentType<{
206
231
  path: string;
@@ -280,6 +305,7 @@ export interface ChatHost {
280
305
  useResumeAtReset(scopeId: string): boolean;
281
306
  useComposerPlaceholder(scopeId: string, chatId: string): string | null;
282
307
  ComposerSlot: ComponentType<ComposerSlotProps> | null;
308
+ useComposerSendActions?(scopeId: string, chatId: string): readonly ComposerSendAction[];
283
309
  SubagentSlot: ComponentType<SubagentSlotProps> | null;
284
310
  useThreadCards(scopeId: string, chatId: string): readonly ThreadCard[];
285
311
  useReplyAuthor(scopeId: string, chatId: string): ReplyAuthor | null;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { type ChatActions, type FileRef, type ShellCodeBlockContext, type ChatPlace, type SubagentTask, type TimelineFindOptions, type TimelineFind, type ComposerDictationProps, type ComposerSlotProps, type SubagentSlotProps, type ThreadCard, type VisualHost, type ReplyAuthor, type ChatHost, type UiMapSource, type UiModelViewProps, type CommandLook, type CommandLookMatch, type CommandName, ChatHostProvider, useChatHost, type AccentChoice, type ChatToast, type TextareaProps, type ResourceUrl } from './host.js';
1
+ export { type ChatActions, type FileRef, type ShellCodeBlockContext, type ChatPlace, type SubagentTask, type TimelineFindOptions, type TimelineFind, type ComposerDictationProps, type ComposerSlotProps, type ComposerSendAction, type ComposerSendDraft, type SubagentSlotProps, type ThreadCard, type VisualHost, type HostMenuAction, type ReplyAuthor, type ChatHost, type UiMapSource, type UiModelViewProps, type CommandLook, type CommandLookMatch, type CommandName, ChatHostProvider, useChatHost, type AccentChoice, type ChatToast, type TextareaProps, type ResourceUrl } from './host.js';
2
2
  export { type ChatScope, ChatScopeContext, useChatScope } from './scope.js';
3
3
  export { type ChatRequestMap, type ChatEventMap, type ChatTransportStatus, type ChatTransport, ChatTransportError, errorCode, isConnectionError } from './transport.js';
4
4
  export { portTransport, type PortTransport } from './port-transport.js';
@@ -391,6 +391,7 @@ declare const _default: {
391
391
  continue: string;
392
392
  continueHint: string;
393
393
  send: string;
394
+ sendActions: string;
394
395
  clear: {
395
396
  title: string;
396
397
  description: string;
@@ -391,6 +391,7 @@ export default {
391
391
  continue: 'Continue',
392
392
  continueHint: 'Continue the stopped turn',
393
393
  send: 'Send',
394
+ sendActions: 'More send options',
394
395
  clear: {
395
396
  title: 'Clear thread?',
396
397
  description: 'A turn is running.',
@@ -391,6 +391,7 @@ declare const _default: {
391
391
  continue: string;
392
392
  continueHint: string;
393
393
  send: string;
394
+ sendActions: string;
394
395
  clear: {
395
396
  title: string;
396
397
  description: string;
@@ -391,6 +391,7 @@ export default {
391
391
  continue: 'Doorgaan',
392
392
  continueHint: 'Ga verder met de gestopte beurt',
393
393
  send: 'Versturen',
394
+ sendActions: 'Meer verzendopties',
394
395
  clear: {
395
396
  title: 'Thread wissen?',
396
397
  description: 'Er loopt een turn.',
@@ -1,5 +1,6 @@
1
1
  export { AccountDot } from '../agents/AccountDot.js';
2
2
  export { AgentIcon } from '../agents/AgentIcon.js';
3
+ export { AgentModelLabel } from '../agents/AgentModelLabel.js';
3
4
  export { ModelOptionControl } from '../agents/ModelOptionControl.js';
4
5
  export { ProviderLogo } from '../agents/ProviderLogo.js';
5
6
  export { type AccountEntry, accountsOfKind, ACCOUNT_TONE_CLASSES, accountStatusLine, canContinueOn, type AccountTone } from '../agents/accounts.js';
@@ -1,6 +1,7 @@
1
1
  // Public API: exports.test.ts snapshots this list, so a name added or dropped here is an API change.
2
2
  export { AccountDot } from '../agents/AccountDot.js';
3
3
  export { AgentIcon } from '../agents/AgentIcon.js';
4
+ export { AgentModelLabel } from '../agents/AgentModelLabel.js';
4
5
  export { ModelOptionControl } from '../agents/ModelOptionControl.js';
5
6
  export { ProviderLogo } from '../agents/ProviderLogo.js';
6
7
  export { accountsOfKind, ACCOUNT_TONE_CLASSES, accountStatusLine, canContinueOn } from '../agents/accounts.js';
package/dist/theme.css CHANGED
@@ -288,6 +288,9 @@
288
288
  .composer-input .cm-editor .cm-scroller .cm-content { padding: 18px 14px 6px 20px; caret-color: var(--text); }
289
289
  .composer-input .cm-scroller .cm-content .cm-line { padding: 0; }
290
290
  .composer-input .cm-scroller .cm-content .cm-placeholder { color: var(--text-faint); }
291
+ /* The same editor as a form field (`PromptEditor`): the field's inset, and room for a few lines before it scrolls. */
292
+ .composer-input.prompt-editor .cm-editor { max-height: 240px; }
293
+ .composer-input.prompt-editor .cm-editor .cm-scroller .cm-content { min-height: 80px; padding: 6px 10px; }
291
294
  .composer-hints, .composer-hints-extra { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
292
295
  /* The joiner starts with its own comma, so it sits against the lead without the gap. */
293
296
  .composer-hints-extra { margin-left: -8px; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adecore/agents-react",
3
- "version": "0.37.3",
3
+ "version": "0.39.0",
4
4
  "description": "React agent chat threads, composers, approvals, provider accounts and usage views.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -67,11 +67,11 @@
67
67
  "test:visuals": "bun --config=integration.bunfig.toml --conditions=source test ./src/chat/visual-viewport.integration.test.ts"
68
68
  },
69
69
  "dependencies": {
70
- "@adecore/agent-contracts": "0.37.3",
71
- "@adecore/editor": "0.37.3",
72
- "@adecore/editor-react": "0.37.3",
73
- "@adecore/intelligent-ui": "0.37.3",
74
- "@adecore/merge": "0.37.3",
70
+ "@adecore/agent-contracts": "0.39.0",
71
+ "@adecore/editor": "0.39.0",
72
+ "@adecore/editor-react": "0.39.0",
73
+ "@adecore/intelligent-ui": "0.39.0",
74
+ "@adecore/merge": "0.39.0",
75
75
  "@codemirror/commands": "^6.11.1",
76
76
  "@codemirror/language": "^6.12.4",
77
77
  "@codemirror/state": "^6.7.6",
@@ -94,14 +94,14 @@
94
94
  "zustand": "^5.0.15"
95
95
  },
96
96
  "peerDependencies": {
97
- "@adecore/ui": "^0.37.3",
97
+ "@adecore/ui": "^0.39.0",
98
98
  "i18next": "^26.4.2",
99
99
  "react": "^19.3.0",
100
100
  "react-dom": "^19.3.0",
101
101
  "react-i18next": "^17.0.15"
102
102
  },
103
103
  "devDependencies": {
104
- "@adecore/ui": "0.37.3",
104
+ "@adecore/ui": "0.39.0",
105
105
  "@types/bun": "^1.4.2",
106
106
  "@types/react": "^19.3.0",
107
107
  "@types/react-dom": "^19.3.0",