@ciridae/ui 1.0.5 → 1.0.9

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 (147) hide show
  1. package/README.md +3 -2
  2. package/dist/chat/conversation-source.d.ts +1 -3
  3. package/dist/chat/message-text.js +6 -6
  4. package/dist/chat/use-chat-conversation.d.ts +7 -2
  5. package/dist/chat/use-chat-conversation.js +2 -1
  6. package/dist/components/activity-feed.d.ts +0 -1
  7. package/dist/components/activity-feed.js +6 -7
  8. package/dist/components/agent-work.d.ts +5 -1
  9. package/dist/components/agent-work.js +27 -13
  10. package/dist/components/app-frame.d.ts +3 -17
  11. package/dist/components/app-frame.js +11 -30
  12. package/dist/components/app-navigation.d.ts +5 -6
  13. package/dist/components/app-navigation.js +65 -40
  14. package/dist/components/badge.d.ts +0 -4
  15. package/dist/components/badge.js +17 -27
  16. package/dist/components/bulk-action-bar.js +2 -2
  17. package/dist/components/button.js +41 -50
  18. package/dist/components/calendar.js +5 -8
  19. package/dist/components/centered-page.js +4 -4
  20. package/dist/components/chart.js +3 -4
  21. package/dist/components/chat-client-source.js +55 -34
  22. package/dist/components/chat-page.js +1 -1
  23. package/dist/components/chat-sheet.d.ts +30 -20
  24. package/dist/components/chat-sheet.js +109 -51
  25. package/dist/components/chat.d.ts +27 -56
  26. package/dist/components/chat.js +151 -129
  27. package/dist/components/checkbox-item.js +4 -4
  28. package/dist/components/checkbox-list.js +6 -6
  29. package/dist/components/chip.js +2 -2
  30. package/dist/components/collapsible.js +3 -3
  31. package/dist/components/color-theme.d.ts +3 -6
  32. package/dist/components/color-theme.js +10 -11
  33. package/dist/components/column-settings.js +3 -3
  34. package/dist/components/command-menu.d.ts +1 -2
  35. package/dist/components/command-menu.js +56 -77
  36. package/dist/components/command-palette.js +5 -2
  37. package/dist/components/copyable-id.js +5 -5
  38. package/dist/components/data-display.d.ts +1 -7
  39. package/dist/components/data-display.js +32 -55
  40. package/dist/components/data-grid.d.ts +4 -7
  41. package/dist/components/data-grid.js +106 -90
  42. package/dist/components/date-range-picker.js +4 -5
  43. package/dist/components/document-viewer.js +23 -23
  44. package/dist/components/drawer.d.ts +2 -1
  45. package/dist/components/drawer.js +45 -20
  46. package/dist/components/dropzone.js +13 -13
  47. package/dist/components/editable-field.d.ts +2 -12
  48. package/dist/components/editable-field.js +13 -26
  49. package/dist/components/email-input.js +2 -3
  50. package/dist/components/environment-frame.js +7 -7
  51. package/dist/components/expandable-text.js +2 -2
  52. package/dist/components/feedback-screenshot.js +7 -7
  53. package/dist/components/feedback-sheet.js +8 -8
  54. package/dist/components/filter-bar.js +41 -27
  55. package/dist/components/form-controls.d.ts +3 -6
  56. package/dist/components/form-controls.js +15 -22
  57. package/dist/components/form-layout.d.ts +6 -6
  58. package/dist/components/form-layout.js +10 -16
  59. package/dist/components/glass-menu.d.ts +2 -0
  60. package/dist/components/glass-menu.js +14 -18
  61. package/dist/components/gradient-edge.d.ts +0 -1
  62. package/dist/components/gradient-edge.js +8 -9
  63. package/dist/components/icon.js +1 -1
  64. package/dist/components/input.js +18 -17
  65. package/dist/components/keycap.d.ts +2 -6
  66. package/dist/components/keycap.js +4 -12
  67. package/dist/components/layout.js +11 -10
  68. package/dist/components/lightbox.js +8 -8
  69. package/dist/components/link.js +1 -1
  70. package/dist/components/locale.d.ts +23 -7
  71. package/dist/components/locale.js +19 -7
  72. package/dist/components/log-entry.d.ts +2 -14
  73. package/dist/components/log-entry.js +11 -22
  74. package/dist/components/log-list.js +1 -1
  75. package/dist/components/mention-input.js +13 -14
  76. package/dist/components/menu.d.ts +7 -4
  77. package/dist/components/menu.js +23 -10
  78. package/dist/components/meter.d.ts +2 -3
  79. package/dist/components/meter.js +12 -16
  80. package/dist/components/navigation.d.ts +0 -7
  81. package/dist/components/navigation.js +3 -12
  82. package/dist/components/notification-tray.js +7 -7
  83. package/dist/components/overlays.d.ts +5 -2
  84. package/dist/components/overlays.js +24 -24
  85. package/dist/components/panel.js +3 -3
  86. package/dist/components/progress.js +2 -2
  87. package/dist/components/radio-card.d.ts +1 -1
  88. package/dist/components/radio-card.js +9 -9
  89. package/dist/components/record.d.ts +2 -4
  90. package/dist/components/record.js +19 -32
  91. package/dist/components/scroll-area.js +10 -10
  92. package/dist/components/segmented-bar.js +9 -9
  93. package/dist/components/select.d.ts +3 -5
  94. package/dist/components/select.js +26 -44
  95. package/dist/components/settings.js +1 -1
  96. package/dist/components/shell-skeleton.js +1 -1
  97. package/dist/components/shell.d.ts +1 -1
  98. package/dist/components/shell.js +69 -24
  99. package/dist/components/side-panel.js +3 -3
  100. package/dist/components/sidebar.d.ts +0 -5
  101. package/dist/components/sidebar.js +25 -33
  102. package/dist/components/single-line-text.js +3 -4
  103. package/dist/components/site-banner.js +4 -4
  104. package/dist/components/skeleton.js +19 -22
  105. package/dist/components/skeletons.d.ts +0 -3
  106. package/dist/components/skeletons.js +5 -10
  107. package/dist/components/stages.d.ts +6 -3
  108. package/dist/components/stages.js +77 -105
  109. package/dist/components/stat-card.d.ts +2 -5
  110. package/dist/components/stat-card.js +23 -31
  111. package/dist/components/status-banner.js +6 -6
  112. package/dist/components/status.js +3 -3
  113. package/dist/components/steps.js +2 -2
  114. package/dist/components/switch.js +1 -1
  115. package/dist/components/tabs.js +15 -18
  116. package/dist/components/theme-customizer.d.ts +5 -8
  117. package/dist/components/theme-customizer.js +9 -41
  118. package/dist/components/theme-toggle.d.ts +0 -1
  119. package/dist/components/theme-toggle.js +6 -11
  120. package/dist/components/toast.d.ts +1 -7
  121. package/dist/components/toast.js +19 -22
  122. package/dist/components/user-chip.js +8 -8
  123. package/dist/components/wizard.js +6 -4
  124. package/dist/preset.d.ts +1 -2
  125. package/dist/preset.js +39 -89
  126. package/dist/styled-system/css/conditions.mjs +1 -1
  127. package/dist/styled-system/css/css.mjs +1 -1
  128. package/dist/styled-system/styles.css +805 -1279
  129. package/dist/styled-system/tokens/index.mjs +74 -1926
  130. package/dist/styled-system/tokens/tokens.d.ts +18 -33
  131. package/dist/styled-system/types/conditions.d.ts +0 -74
  132. package/dist/styled-system/types/prop-type.d.ts +15 -40
  133. package/dist/styled-system/types/style-props.d.ts +705 -705
  134. package/dist/theme/color.d.ts +0 -1
  135. package/dist/theme/color.js +0 -16
  136. package/dist/theme/derive.d.ts +3 -3
  137. package/dist/theme/derive.js +9 -32
  138. package/dist/theme/index.d.ts +1 -2
  139. package/dist/theme/index.js +3 -5
  140. package/dist/theme/options.d.ts +2 -4
  141. package/dist/theme/options.js +0 -1
  142. package/dist/theme/{palettes.d.ts → palette.d.ts} +12 -23
  143. package/dist/theme/palette.js +127 -0
  144. package/dist/theme/tokens.d.ts +8 -13
  145. package/dist/theme/tokens.js +38 -92
  146. package/package.json +1 -1
  147. package/dist/theme/palettes.js +0 -254
@@ -6,13 +6,12 @@ import { IconButton } from "./button.js";
6
6
  import { directional, icon } from "./icon.js";
7
7
  import { useCiridaeLocale } from "./locale.js";
8
8
  /*
9
- * The month alone, no face of its own: it sits on the popover or picker that opens it. Seven 32px
10
- * day columns inside an 8px inset, which with the glass sheet's 4px makes the design's 12px.
9
+ * Seven 32px day columns inside an 8px inset, which with the glass sheet's 4px makes the design's 12px.
11
10
  */
12
11
  const calendar = css({
13
12
  display: "grid",
14
13
  gap: "layout.controlGap",
15
- width: "calc(7 * token(sizes.control.compact) + 2 * token(spacing.panel.compact))",
14
+ width: "[calc(7 * token(sizes.control.compact) + 2 * token(spacing.panel.compact))]",
16
15
  padding: "panel.compact",
17
16
  });
18
17
  const header = css({
@@ -29,7 +28,6 @@ const grid = css({
29
28
  justifyItems: "center",
30
29
  rowGap: "control.trackInset",
31
30
  });
32
- // The weekdays sit as far above the days as the month sits above them.
33
31
  const weekDay = css({
34
32
  paddingBlock: "layout.tightGap",
35
33
  marginBottom: "control.iconGap",
@@ -43,10 +41,9 @@ const row = css({
43
41
  display: "grid",
44
42
  gridColumn: "1 / -1",
45
43
  gridTemplateColumns: "subgrid",
46
- width: "100%",
44
+ width: "full",
47
45
  });
48
46
  const previousMonthIcon = css({ transform: "rotate(180deg)" });
49
- // Today wears a hairline ring; the chosen day the primary button's face.
50
47
  const day = css({
51
48
  width: "control.compact",
52
49
  height: "control.compact",
@@ -57,7 +54,7 @@ const day = css({
57
54
  fontSize: "caption",
58
55
  fontWeight: "medium",
59
56
  cursor: "pointer",
60
- transitionProperty: "background, color",
57
+ transitionProperty: "[background, color]",
61
58
  transitionDuration: "fast",
62
59
  "&[aria-current=date]": { borderColor: "border.control" },
63
60
  "&:hover:not(:disabled):not([aria-selected=true])": {
@@ -65,7 +62,7 @@ const day = css({
65
62
  },
66
63
  "&[aria-selected=true]": {
67
64
  borderColor: "transparent",
68
- background: "token(gradients.primary)",
65
+ background: "[token(gradients.primary)]",
69
66
  color: "bg.canvas",
70
67
  _light: { color: "fg.onAccent" },
71
68
  },
@@ -3,21 +3,21 @@ import { css, cx } from "#primitives/css";
3
3
  import { CiridaeMark } from "./brand-icons.js";
4
4
  const page = css({
5
5
  boxSizing: "border-box",
6
- minHeight: "100dvh",
6
+ minHeight: "[100dvh]",
7
7
  display: "flex",
8
8
  alignItems: "center",
9
9
  justifyContent: "center",
10
10
  // A phone keeps a thin margin around the card rather than giving its width away.
11
11
  padding: "panel.compact",
12
12
  "@media(min-width: 640px)": { padding: "page.inline" },
13
- background: "token(gradients.canvas)",
13
+ background: "[token(gradients.canvas)]",
14
14
  color: "fg.primary",
15
15
  });
16
16
  const column = css({
17
17
  display: "flex",
18
18
  flexDirection: "column",
19
19
  gap: "layout.contentGap",
20
- width: "100%",
20
+ width: "full",
21
21
  maxWidth: "card.centered",
22
22
  });
23
23
  const formColumn = css({ maxWidth: "card.centeredForm" });
@@ -37,7 +37,7 @@ const titleText = css({ margin: "none", fontSize: "heading.section", fontWeight:
37
37
  const descriptionText = css({ margin: "none", color: "fg.muted", fontSize: "caption" });
38
38
  const card = css({
39
39
  boxSizing: "border-box",
40
- width: "100%",
40
+ width: "full",
41
41
  padding: "panel.roomy",
42
42
  borderRadius: "card",
43
43
  border: "1px solid token(colors.border.card)",
@@ -39,10 +39,10 @@ const tooltipBody = css({
39
39
  display: "grid",
40
40
  gap: "control.trackInset",
41
41
  padding: "panel.compact",
42
- border: "1px solid token(colors.border.control)",
42
+ border: "1px solid token(colors.border.popover)",
43
43
  borderRadius: "action",
44
44
  background: "bg.popover",
45
- backdropFilter: "blur(token(blurs.popover))",
45
+ backdropFilter: "[blur(token(blurs.popover))]",
46
46
  boxShadow: "soft",
47
47
  color: "fg.primary",
48
48
  fontFamily: "sans",
@@ -72,7 +72,7 @@ const legendItem = css({
72
72
  alignItems: "center",
73
73
  gap: "control.iconGap",
74
74
  minWidth: "0",
75
- maxWidth: "100%",
75
+ maxWidth: "full",
76
76
  "& > span:last-child": {
77
77
  overflow: "hidden",
78
78
  textOverflow: "ellipsis",
@@ -264,7 +264,6 @@ export function CategoryChart({ categories, series, variant = "bar", formatValue
264
264
  }, [allowDecimals, categories, formatValue, series, variant]);
265
265
  return (_jsxs("div", { ...props, className: cx(frame, className), "data-ciridae-ui": "", "data-variant": variant, children: [_jsx(Chart, { ariaLabel: series.map((item) => item.label).join(", "), definition: definition, height: height, renderTooltipBody: ({ points, content }) => (_jsx(SeriesTooltip, { content: content, points: points, series: series, formatValue: formatValue })) }), _jsx(SeriesLegend, { series: series })] }));
266
266
  }
267
- /** Each series index to its chart colour, in order. */
268
267
  function seriesColorScale(count) {
269
268
  return scaleOrdinal()
270
269
  .domain(Array.from({ length: count }, (_, index) => index))
@@ -15,7 +15,7 @@ import { useCiridaeLocale } from "./locale.js";
15
15
  const card = css({
16
16
  display: "grid",
17
17
  gap: "control.iconGap",
18
- width: "100%",
18
+ width: "full",
19
19
  maxWidth: "chat.bubble",
20
20
  paddingBlock: "control.block",
21
21
  paddingInline: "control.compactInline",
@@ -26,24 +26,34 @@ const card = css({
26
26
  lineHeight: "log",
27
27
  });
28
28
  const cardLabel = css({ color: "fg.muted", fontSize: "code", lineHeight: "compact" });
29
+ // Every name and value shows in full, wrapped, since the person deciding has to see what runs.
29
30
  const argumentList = css({
30
31
  display: "grid",
31
- gridTemplateColumns: "auto minmax(0, 1fr)",
32
+ gridTemplateColumns: "fit-content(40%) minmax(0, 1fr)",
32
33
  columnGap: "layout.controlGap",
33
34
  margin: "none",
34
35
  fontSize: "code",
35
36
  lineHeight: "compact",
36
- "& > dt": { color: "fg.muted", whiteSpace: "nowrap" },
37
- "& > dd": { margin: "none", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
37
+ "& > dt": { color: "fg.muted", overflowWrap: "anywhere" },
38
+ "& > dd": { margin: "none", whiteSpace: "pre-wrap", overflowWrap: "anywhere" },
38
39
  });
40
+ const rawArguments = css({
41
+ margin: "none",
42
+ fontFamily: "mono",
43
+ fontSize: "code",
44
+ lineHeight: "compact",
45
+ whiteSpace: "pre-wrap",
46
+ overflowWrap: "anywhere",
47
+ });
48
+ const decisionError = css({ color: "accent.red", fontSize: "code", lineHeight: "compact" });
39
49
  const cardActions = css({ display: "flex", justifyContent: "flex-end", gap: "layout.controlGap" });
40
50
  // Option rows run to the card's edges, split by its hairlines.
41
51
  const optionList = css({
42
- marginInline: "calc(token(spacing.control.compactInline) * -1)",
43
- marginBlockEnd: "calc(token(spacing.control.block) * -1)",
52
+ marginInline: "[calc(token(spacing.control.compactInline) * -1)]",
53
+ marginBlockEnd: "[calc(token(spacing.control.block) * -1)]",
44
54
  "& > button": {
45
55
  display: "block",
46
- width: "100%",
56
+ width: "full",
47
57
  paddingBlock: "control.compactBlock",
48
58
  paddingInline: "control.compactInline",
49
59
  border: "0",
@@ -59,21 +69,16 @@ const optionList = css({
59
69
  },
60
70
  });
61
71
  const optionDetail = css({ display: "block", color: "fg.muted", fontSize: "code" });
62
- /** How many of an approval's arguments show before the rest become "+N". */
63
- const maximumArgumentRows = 3;
64
72
  /** One conversation of the lib's chat client, polled while its response runs. */
65
73
  export function useChatClientSource({ client, conversationId, onConversationCreated, }) {
66
74
  const { labels } = useCiridaeLocale();
67
75
  const state = useChatConversation({ client, conversationId, onConversationCreated });
68
- const [sendError, setSendError] = useState(null);
69
76
  // The uploads the composer holds by id, so a message sends the service's own records.
70
77
  const uploadsRef = useRef(new Map());
71
78
  const send = (content, attachments) => {
72
- setSendError(null);
73
- // The message shows as sending at once, and as not sent with its retry if it fails.
74
- state.sendMessage(content, attachments).catch((error) => {
75
- setSendError(error instanceof Error ? error.message : String(error));
76
- });
79
+ // The message shows as sending at once, and if it fails, as not sent with its own error and
80
+ // its retry, so the rejection has nothing more to tell.
81
+ state.sendMessage(content, attachments).catch(() => undefined);
77
82
  };
78
83
  const toChatAttachment = (attachment) => ({
79
84
  id: attachment.id,
@@ -93,7 +98,6 @@ export function useChatClientSource({ client, conversationId, onConversationCrea
93
98
  ? items.filter((item) => item.type === "message" && item.role === "user" && item.response_id === response.id)
94
99
  : [];
95
100
  const lastUserMessage = failedTurnMessages[failedTurnMessages.length - 1];
96
- // How each tool call ended, by its call id; a call with none has not returned yet.
97
101
  const callStatuses = new Map(items.flatMap((item) => item.type === "function_call_output" ? [[item.call_id, item.status]] : []));
98
102
  const lastItem = items[items.length - 1];
99
103
  const conversationItems = [];
@@ -126,7 +130,7 @@ export function useChatClientSource({ client, conversationId, onConversationCrea
126
130
  sending: message.state === "sending",
127
131
  failure: message.state === "failed"
128
132
  ? {
129
- message: sendError ?? labels.chat.notSent,
133
+ message: message.failureMessage || labels.chat.notSent,
130
134
  retry: () => {
131
135
  state.discardPendingMessage(message.localId);
132
136
  send(message.content, message.attachments);
@@ -164,10 +168,6 @@ export function useChatClientConversations(client) {
164
168
  }))), [list.data]);
165
169
  return { conversations, loading: list.isPending };
166
170
  }
167
- /**
168
- * An item as the thread draws it. A tool call is a step named by its tool, with how it ended and
169
- * neither its arguments nor its output; a thought is a step named by its first line.
170
- */
171
171
  function toConversationItem(item, { waitingOnUser, inRunningTurn, newest, callStatuses, toChatAttachment, answered, decided, decideApproval, answerQuestion, }) {
172
172
  const at = Date.parse(item.created_at);
173
173
  switch (item.type) {
@@ -252,11 +252,23 @@ function toConversationItem(item, { waitingOnUser, inRunningTurn, newest, callSt
252
252
  }
253
253
  }
254
254
  }
255
- /** A tool call waiting for the user: what it would do, its arguments, and Deny or Allow. */
255
+ /**
256
+ * A tool call waiting for the user: what it would do, every one of its arguments, and Deny or
257
+ * Allow. A decision the service refuses shows its error on the card, which waits for another.
258
+ */
256
259
  function ApprovalCard({ item, onDecide, }) {
257
260
  const { labels } = useCiridaeLocale();
258
- const rows = listArgumentRows(item.arguments);
259
- return (_jsxs("div", { className: card, children: [_jsx("span", { children: describeToolCall(item.tool) }), rows.length > 0 && (_jsxs("dl", { className: argumentList, children: [rows.slice(0, maximumArgumentRows).map(([name, value]) => (_jsxs(Fragment, { children: [_jsx("dt", { children: name }), _jsx("dd", { children: value })] }, name))), rows.length > maximumArgumentRows && (_jsxs("dd", { className: cardLabel, children: ["+", rows.length - maximumArgumentRows] }))] })), _jsxs("div", { className: cardActions, children: [_jsx(Button, { variant: "secondary", onClick: () => void onDecide(item, "deny"), children: labels.chat.deny }), _jsx(Button, { onClick: () => void onDecide(item, "allow"), children: labels.chat.allow })] })] }));
261
+ const [decisionState, setDecisionState] = useState({ kind: "undecided" });
262
+ const callArguments = readApprovalArguments(item.arguments);
263
+ const decide = (decision) => {
264
+ setDecisionState({ kind: "sending", decision });
265
+ onDecide(item, decision).catch((error) => setDecisionState({
266
+ kind: "failed",
267
+ message: error instanceof Error ? error.message : String(error),
268
+ }));
269
+ };
270
+ const sending = decisionState.kind === "sending";
271
+ return (_jsxs("div", { className: card, children: [_jsx("span", { children: describeToolCall(item.tool) }), callArguments.kind === "rows" && callArguments.rows.length > 0 && (_jsx("dl", { className: argumentList, children: callArguments.rows.map((row) => (_jsxs(Fragment, { children: [_jsx("dt", { children: row.label }), _jsx("dd", { children: row.value })] }, row.name))) })), callArguments.kind === "text" && callArguments.text.trim() && (_jsx("pre", { className: rawArguments, children: callArguments.text })), decisionState.kind === "failed" && (_jsx("span", { className: decisionError, role: "alert", children: decisionState.message })), _jsxs("div", { className: cardActions, children: [_jsx(Button, { variant: "secondary", disabled: sending, loading: sending && decisionState.decision === "deny", onClick: () => decide("deny"), children: labels.chat.deny }), _jsx(Button, { disabled: sending, loading: sending && decisionState.decision === "allow", onClick: () => decide("allow"), children: labels.chat.allow })] })] }));
260
272
  }
261
273
  /** The assistant's questions, one option row per answer; picking one answers that question. */
262
274
  function QuestionCard({ item, onAnswer, }) {
@@ -280,18 +292,27 @@ function isSameMessage(item, message) {
280
292
  item.content === message.content &&
281
293
  Date.parse(item.created_at) >= message.sentAt - 60000);
282
294
  }
283
- /** A call's JSON arguments as name and value pairs, values shortened to one line. */
284
- function listArgumentRows(argumentsJson) {
295
+ /**
296
+ * A call's arguments as the card shows them: a JSON object as one name and value row per key,
297
+ * anything else as the text the call carries.
298
+ */
299
+ function readApprovalArguments(argumentsJson) {
300
+ let parsed;
285
301
  try {
286
- const parsed = JSON.parse(argumentsJson);
287
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
288
- return [];
289
- return Object.entries(parsed).map(([name, value]) => [
290
- name.replace(/[_-]+/g, " "),
291
- typeof value === "string" ? value : JSON.stringify(value),
292
- ]);
302
+ parsed = JSON.parse(argumentsJson);
293
303
  }
294
304
  catch {
295
- return [];
305
+ return { kind: "text", text: argumentsJson };
296
306
  }
307
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
308
+ return { kind: "text", text: argumentsJson };
309
+ }
310
+ return {
311
+ kind: "rows",
312
+ rows: Object.entries(parsed).map(([name, value]) => ({
313
+ name,
314
+ label: name.replace(/[_-]+/g, " "),
315
+ value: typeof value === "string" ? value : JSON.stringify(value),
316
+ })),
317
+ };
297
318
  }
@@ -90,7 +90,7 @@ const historyRow = css({
90
90
  display: "flex",
91
91
  alignItems: "center",
92
92
  gap: "layout.controlGap",
93
- width: "100%",
93
+ width: "full",
94
94
  height: "menu.item",
95
95
  paddingInline: "menu.itemInline",
96
96
  border: "0",
@@ -21,16 +21,7 @@ export type ChatSheetEvent = {
21
21
  text: string;
22
22
  };
23
23
  /** The thread and composer's own props, shared by the sheet and `ChatConversation`. */
24
- export type ChatConversationProps = {
25
- /**
26
- * `agent`, the default, is the main agent's one long-running thread, with its `tasks` as cards
27
- * under day labels; `conversations` is one conversation of many, such as beside `ChatHistory`.
28
- */
29
- variant?: "agent" | "conversations";
30
- /** What the main agent runs on its own, oldest first; `agent` only. */
31
- tasks?: readonly AgentTask[];
32
- /** The user's approval or answer on a waiting task's card. */
33
- onTaskReply?: (task: AgentTask, reply: AgentTaskReply) => void;
24
+ type ChatThreadAndComposerProps = {
34
25
  /** The conversation: `useChatClientSource` over the lib's chat client, or the app's own. */
35
26
  source: ChatConversationSource;
36
27
  placeholder: string;
@@ -55,12 +46,35 @@ export type ChatConversationProps = {
55
46
  suggestions?: readonly string[];
56
47
  /** A Copy control in the footer of each reply once its turn has finished, and not failed. */
57
48
  copyReplies?: boolean;
58
- /** More tools in the composer's bar after the paperclip, such as a dictation button. */
59
49
  composerTools?: ReactNode;
60
- /** While the host takes dictation, its levels as the composer's waveform; see `ChatComposer`. */
61
50
  dictation?: ChatDictation;
51
+ } & (({
52
+ /** The default: the main agent's one long-running thread, its `tasks` as cards by day. */
53
+ variant?: "agent";
54
+ } & ({
55
+ tasks?: never;
56
+ onTaskReply?: never;
57
+ } | {
58
+ /** What the main agent runs on its own, oldest first. */
59
+ tasks: readonly AgentTask[];
60
+ /**
61
+ * Sends the user's approval or answer on a waiting task's card, as `AgentTaskCard`'s
62
+ * `onReply` does; every waiting task needs it, so it comes with `tasks`.
63
+ */
64
+ onTaskReply: (task: AgentTask, reply: AgentTaskReply) => Promise<void>;
65
+ })) | {
66
+ /** One conversation of many, such as beside `ChatHistory`; it has no tasks. */
67
+ variant: "conversations";
68
+ tasks?: never;
69
+ onTaskReply?: never;
70
+ });
71
+ export type ChatConversationProps = ChatThreadAndComposerProps & {
72
+ /** `wide` sets the thread and composer in one readable column for a full page. */
73
+ layout?: "sheet" | "wide";
74
+ /** The drawer's body inside a `Drawer`, a plain element otherwise. */
75
+ scrollBody?: typeof DrawerBody | "div";
62
76
  };
63
- export type ChatSheetProps = ChatConversationProps & {
77
+ export type ChatSheetProps = ChatThreadAndComposerProps & {
64
78
  open: boolean;
65
79
  onOpenChange: (open: boolean) => void;
66
80
  title: ReactNode;
@@ -72,16 +86,12 @@ export type ChatSheetProps = ChatConversationProps & {
72
86
  onPlacementChange?: (placement: ChatSheetPlacement) => void;
73
87
  /** Shows a header button that moves the conversation to a full page. */
74
88
  onOpenFullPage?: () => void;
75
- /** The hotkey that opens the sheet, shown as keys in its header. */
76
89
  shortcut?: HotkeyChord;
77
90
  };
78
91
  export declare function ChatSheet({ open, onOpenChange, title, context, placement, onPlacementChange, onOpenFullPage, shortcut, ...conversationProps }: ChatSheetProps): import("react").JSX.Element | null;
79
92
  /**
80
93
  * The thread and the composer: everything that reads or writes the conversation. `layout="wide"`
81
- * sets both in one readable column for a full page; the sheet uses `sheet`.
94
+ * sets both in one readable column for a full page; the sheet uses `sheet`. Only the `agent`
95
+ * variant takes `tasks`.
82
96
  */
83
- export declare function ChatConversation({ source, placeholder, draft, onDraftChange, composerRef, mentions, mentionMark, onMentionSelect, mentionHref, events, assistantName: ownAssistantName, suggestions, copyReplies, composerTools, dictation, variant, tasks, onTaskReply, layout, scrollBody: ScrollBody, }: ChatConversationProps & {
84
- layout?: "sheet" | "wide";
85
- /** The drawer's body inside a `Drawer`, a plain element otherwise. */
86
- scrollBody?: typeof DrawerBody | "div";
87
- }): import("react").JSX.Element;
97
+ export declare function ChatConversation({ source, placeholder, draft, onDraftChange, composerRef, mentions, mentionMark, onMentionSelect, mentionHref, events, assistantName: ownAssistantName, suggestions, copyReplies, composerTools, dictation, tasks, onTaskReply, layout, scrollBody: ScrollBody, }: ChatConversationProps): import("react").JSX.Element;