@parallelworks/ui 0.51.0 → 0.52.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 (227) hide show
  1. package/README.md +155 -14
  2. package/dist/ai/agent/toolStrings.d.ts +2 -0
  3. package/dist/ai/agent/toolStrings.js +20 -18
  4. package/dist/ai/ai.css +12 -0
  5. package/dist/ai/components/AllocationSelector.js +5 -1
  6. package/dist/ai/components/AttachmentManager.js +51 -42
  7. package/dist/ai/components/AttachmentUpload.d.ts +4 -2
  8. package/dist/ai/components/AttachmentUpload.js +9 -9
  9. package/dist/ai/components/BlockedGroupBanner.js +8 -14
  10. package/dist/ai/components/BranchNavigator.js +11 -12
  11. package/dist/ai/components/ChatEmptyState.js +12 -19
  12. package/dist/ai/components/ChatInput.d.ts +4 -3
  13. package/dist/ai/components/ChatInput.js +27 -13
  14. package/dist/ai/components/ChatMessage.js +45 -121
  15. package/dist/ai/components/ChatMessageList.d.ts +5 -2
  16. package/dist/ai/components/ChatMessageList.js +89 -51
  17. package/dist/ai/components/ChatSidebar.js +11 -7
  18. package/dist/ai/components/ChatThread.js +1 -13
  19. package/dist/ai/components/DragOverlay.js +3 -3
  20. package/dist/ai/components/MessageAttachments.d.ts +10 -0
  21. package/dist/ai/components/MessageAttachments.js +78 -0
  22. package/dist/ai/components/ModelSelector.js +3 -3
  23. package/dist/ai/components/PastedText.js +2 -2
  24. package/dist/ai/components/ProviderIssueBanner.js +19 -23
  25. package/dist/ai/components/ShareDialog.js +2 -2
  26. package/dist/ai/components/agent/ActivityLine.d.ts +0 -2
  27. package/dist/ai/components/agent/ActivityLine.js +8 -51
  28. package/dist/ai/components/agent/AgentMessageParts.js +114 -53
  29. package/dist/ai/core/ChatProvider.d.ts +16 -5
  30. package/dist/ai/core/ChatProvider.js +41 -8
  31. package/dist/ai/core/config.js +4 -3
  32. package/dist/ai/index.d.ts +1 -1
  33. package/dist/ai/index.js +3 -3
  34. package/dist/ai/strings.d.ts +29 -3
  35. package/dist/ai/strings.js +81 -26
  36. package/dist/ai/types.d.ts +4 -0
  37. package/dist/ai/ui/Notice.d.ts +2 -2
  38. package/dist/ai/ui/Notice.js +29 -62
  39. package/dist/ai/ui/sidebar.d.ts +5 -3
  40. package/dist/ai/ui/sidebar.js +21 -9
  41. package/dist/components/ActionMenu.d.ts +1 -0
  42. package/dist/components/ActionMenu.js +6 -1
  43. package/dist/components/AppLink.d.ts +26 -0
  44. package/dist/components/AppLink.js +51 -0
  45. package/dist/components/Avatar.d.ts +2 -1
  46. package/dist/components/Avatar.js +4 -2
  47. package/dist/components/Button.d.ts +15 -5
  48. package/dist/components/Button.js +47 -40
  49. package/dist/components/Callout.d.ts +31 -7
  50. package/dist/components/Callout.js +50 -19
  51. package/dist/components/Card.d.ts +11 -6
  52. package/dist/components/Card.js +14 -8
  53. package/dist/components/Checkbox.js +2 -1
  54. package/dist/components/ColorInput.js +5 -3
  55. package/dist/components/Combobox.js +49 -19
  56. package/dist/components/ConfirmModal.d.ts +19 -8
  57. package/dist/components/ConfirmModal.js +31 -53
  58. package/dist/components/CopyButton.d.ts +38 -0
  59. package/dist/components/CopyButton.js +68 -0
  60. package/dist/components/CreateModal.js +118 -111
  61. package/dist/components/DatePicker.js +12 -8
  62. package/dist/components/DescriptionList.d.ts +25 -5
  63. package/dist/components/DescriptionList.js +56 -22
  64. package/dist/components/Disclosure.js +1 -1
  65. package/dist/components/Drawer.js +10 -16
  66. package/dist/components/Field.d.ts +15 -5
  67. package/dist/components/Field.js +40 -8
  68. package/dist/components/IconButton.d.ts +14 -5
  69. package/dist/components/IconButton.js +25 -14
  70. package/dist/components/InfoTip.d.ts +4 -1
  71. package/dist/components/InfoTip.js +2 -1
  72. package/dist/components/Input.d.ts +14 -8
  73. package/dist/components/Input.js +46 -31
  74. package/dist/components/Loader.js +1 -1
  75. package/dist/components/MenuEntries.d.ts +4 -0
  76. package/dist/components/MenuEntries.js +11 -12
  77. package/dist/components/Meter.js +5 -4
  78. package/dist/components/Modal.d.ts +28 -4
  79. package/dist/components/Modal.js +37 -14
  80. package/dist/components/Overview.d.ts +20 -12
  81. package/dist/components/Overview.js +14 -9
  82. package/dist/components/PageHeader.d.ts +47 -65
  83. package/dist/components/PageHeader.js +275 -153
  84. package/dist/components/PageHeaderAction.d.ts +67 -0
  85. package/dist/components/PageHeaderAction.js +107 -0
  86. package/dist/components/Pagination.js +6 -16
  87. package/dist/components/Popover.js +3 -2
  88. package/dist/components/Provider.d.ts +77 -19
  89. package/dist/components/Provider.js +139 -130
  90. package/dist/components/Radio.js +2 -1
  91. package/dist/components/RefreshButton.js +7 -8
  92. package/dist/components/RequiredMark.js +1 -1
  93. package/dist/components/Section.js +1 -1
  94. package/dist/components/Select.d.ts +4 -9
  95. package/dist/components/Select.js +24 -11
  96. package/dist/components/SettingModeOption.d.ts +1 -1
  97. package/dist/components/SettingModeOption.js +7 -1
  98. package/dist/components/SettingsCard.d.ts +5 -3
  99. package/dist/components/SettingsCard.js +27 -20
  100. package/dist/components/Slider.js +1 -1
  101. package/dist/components/StatusBadge.js +2 -2
  102. package/dist/components/Switch.js +5 -4
  103. package/dist/components/Table.d.ts +30 -20
  104. package/dist/components/Table.js +50 -73
  105. package/dist/components/Tabs.d.ts +3 -7
  106. package/dist/components/Tabs.js +6 -10
  107. package/dist/components/ThemeEditor.js +18 -8
  108. package/dist/components/Toast.d.ts +11 -3
  109. package/dist/components/Toast.js +45 -20
  110. package/dist/components/buttonClasses.js +1 -1
  111. package/dist/components/comboboxItems.d.ts +4 -0
  112. package/dist/components/comboboxItems.js +6 -1
  113. package/dist/components/dismiss.d.ts +12 -0
  114. package/dist/components/dismiss.js +19 -0
  115. package/dist/components/fieldBox.d.ts +4 -0
  116. package/dist/components/fieldBox.js +7 -3
  117. package/dist/components/floating.d.ts +3 -3
  118. package/dist/components/floating.js +1 -1
  119. package/dist/components/markdownCodeBreaks.js +3 -4
  120. package/dist/components/pageHeaderStore.d.ts +41 -0
  121. package/dist/components/pageHeaderStore.js +67 -0
  122. package/dist/components/pathBreaks.d.ts +8 -0
  123. package/dist/components/pathBreaks.js +28 -0
  124. package/dist/components/segmented.js +1 -1
  125. package/dist/components/shortcutKey.d.ts +2 -1
  126. package/dist/components/shortcutKey.js +19 -2
  127. package/dist/components/splitter.js +1 -1
  128. package/dist/components/useCssIsDark.js +40 -18
  129. package/dist/components/useTheme.js +9 -10
  130. package/dist/dev.d.ts +9 -0
  131. package/dist/dev.js +14 -0
  132. package/dist/editor/Editor.d.ts +3 -2
  133. package/dist/editor/Editor.js +11 -2
  134. package/dist/editor/EditorField.d.ts +2 -1
  135. package/dist/editor/EditorField.js +11 -29
  136. package/dist/editor/FormCodePanel.d.ts +7 -3
  137. package/dist/editor/FormCodePanel.js +14 -7
  138. package/dist/editor/Monaco.d.ts +14 -5
  139. package/dist/editor/Monaco.js +163 -112
  140. package/dist/editor/index.d.ts +5 -5
  141. package/dist/editor/index.js +3 -3
  142. package/dist/editor/themes.d.ts +8 -5
  143. package/dist/editor/themes.js +58 -30
  144. package/dist/editor/yaml.d.ts +6 -2
  145. package/dist/editor/yaml.js +11 -2
  146. package/dist/file-explorer/FileExplorer.js +143 -124
  147. package/dist/file-explorer/FileExplorerContext.js +1 -1
  148. package/dist/file-explorer/FilePreview/StreamedBadge.js +3 -1
  149. package/dist/file-explorer/FilePreview/Viewer.js +2 -2
  150. package/dist/file-explorer/FilePreview/index.js +4 -4
  151. package/dist/file-explorer/FileRow.js +1 -1
  152. package/dist/file-explorer/FileRowsWindow.js +34 -3
  153. package/dist/file-explorer/FileTable.js +3 -1
  154. package/dist/file-explorer/TreeView.js +37 -14
  155. package/dist/file-explorer/helpers.d.ts +2 -1
  156. package/dist/file-explorer/helpers.js +21 -20
  157. package/dist/file-explorer/toasts.js +27 -19
  158. package/dist/file-explorer/treeRows.d.ts +6 -0
  159. package/dist/file-explorer/treeRows.js +19 -1
  160. package/dist/file-explorer/useNearEnd.js +3 -6
  161. package/dist/form/Fields/CheckboxGroupField.js +12 -5
  162. package/dist/form/Fields/DurationField.js +1 -1
  163. package/dist/form/Fields/LabelField.js +1 -1
  164. package/dist/form/Fields/ObjectField.d.ts +1 -1
  165. package/dist/form/Fields/ObjectField.js +3 -2
  166. package/dist/form/Fields/StringField.js +16 -29
  167. package/dist/form/Fields/TextAreaField.js +3 -4
  168. package/dist/form/Form.js +3 -8
  169. package/dist/form/Wizard/WizardNavigation.js +0 -3
  170. package/dist/form/Wizard/utils.js +1 -1
  171. package/dist/form/fieldFrame.d.ts +1 -1
  172. package/dist/form/fieldFrame.js +2 -2
  173. package/dist/form/types/fieldComponentTypes.d.ts +2 -1
  174. package/dist/graph/AnnotationBanner.d.ts +1 -2
  175. package/dist/graph/AnnotationBanner.js +30 -32
  176. package/dist/graph/Connectors.js +4 -1
  177. package/dist/graph/DependencyGraph.js +2 -2
  178. package/dist/graph/GraphEditor.js +11 -9
  179. package/dist/graph/GraphEditorDialogs.js +1 -1
  180. package/dist/graph/GraphNode.js +7 -4
  181. package/dist/graph/InputDialog.js +1 -1
  182. package/dist/graph/InputsEditor.js +14 -11
  183. package/dist/graph/MatrixGroup.js +9 -3
  184. package/dist/graph/Reveal.js +18 -10
  185. package/dist/graph/ShortcutsButton.d.ts +11 -2
  186. package/dist/graph/ShortcutsButton.js +14 -3
  187. package/dist/graph/TreeView.js +35 -18
  188. package/dist/graph/WorkflowSettingsDialog.js +1 -1
  189. package/dist/graph/editorFields.js +1 -1
  190. package/dist/graph/editorRows.js +16 -10
  191. package/dist/graph/editorStrings.d.ts +7 -0
  192. package/dist/graph/editorStrings.js +8 -1
  193. package/dist/graph/inputRefs.js +1 -1
  194. package/dist/graph/settingsViews.js +11 -18
  195. package/dist/graph/stepWith.js +1 -1
  196. package/dist/icons.d.ts +2 -0
  197. package/dist/icons.js +4 -2
  198. package/dist/index.d.ts +12 -12
  199. package/dist/index.js +16 -16
  200. package/dist/list/ActionToolbar.d.ts +42 -6
  201. package/dist/list/ActionToolbar.js +297 -101
  202. package/dist/list/ListPage.d.ts +15 -23
  203. package/dist/list/ListPage.js +42 -43
  204. package/dist/list/ListTable.d.ts +32 -7
  205. package/dist/list/ListTable.js +48 -12
  206. package/dist/list/ListViewControls.js +1 -1
  207. package/dist/list/UserHoverCard.js +7 -15
  208. package/dist/list/index.d.ts +2 -2
  209. package/dist/list/index.js +2 -2
  210. package/dist/list/listSearch.js +12 -10
  211. package/dist/list/listView.d.ts +10 -1
  212. package/dist/list/listView.js +15 -1
  213. package/dist/logviewer/LogViewer.d.ts +4 -2
  214. package/dist/logviewer/LogViewer.js +87 -69
  215. package/dist/logviewer/logviewer.css +3 -2
  216. package/dist/reducedMotion.d.ts +5 -0
  217. package/dist/reducedMotion.js +20 -0
  218. package/dist/safeUrl.d.ts +1 -1
  219. package/dist/safeUrl.js +4 -2
  220. package/dist/styles.css +1 -1
  221. package/package.json +1 -1
  222. package/dist/components/Breadcrumbs.d.ts +0 -37
  223. package/dist/components/Breadcrumbs.js +0 -90
  224. package/dist/components/CopyToClipboard.d.ts +0 -17
  225. package/dist/components/CopyToClipboard.js +0 -66
  226. package/dist/components/Sort.d.ts +0 -9
  227. package/dist/components/Sort.js +0 -42
@@ -1,6 +1,7 @@
1
1
  import { cx } from "../../../cx.js";
2
2
  import { CheckIcon } from "../../../icons.js";
3
3
  import { Loader } from "../../../components/Loader.js";
4
+ import { toneSurface } from "../../../components/tone.js";
4
5
  import { useStrings } from "../../../components/Provider.js";
5
6
  import { fieldBox } from "../../../components/fieldBox.js";
6
7
  import { Disclosure } from "../../../components/Disclosure.js";
@@ -11,11 +12,12 @@ import { computeEditDiff, computeWriteRows, editSummary, isEditDiffTool, parseEd
11
12
  import { languageForPath, tokenizeDiffLines } from "../../agent/diffHighlight.js";
12
13
  import { thinkingHeading } from "../../agent/transcript.js";
13
14
  import { useChatConfig } from "../../core/config.js";
15
+ import { focusOnMount } from "../../../components/focus.js";
14
16
  import Markdown from "../../ui/Markdown.js";
15
17
  import { chatProseClasses } from "../../ui/prose.js";
16
18
  import { Reasoning, ReasoningBody } from "../Reasoning.js";
17
19
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
18
- import { useEffect, useMemo, useState } from "react";
20
+ import { memo, useEffect, useId, useMemo, useState } from "react";
19
21
  //#region src/ai/components/agent/AgentMessageParts.tsx
20
22
  var COLLAPSED_RESULT_LINES = 12;
21
23
  function LineSpans({ text, tokens, emphasis }) {
@@ -35,7 +37,7 @@ function LineSpans({ text, tokens, emphasis }) {
35
37
  let end = start + 1;
36
38
  while (end < t.content.length && inEmphasis(offset + end) === emphasized) end++;
37
39
  out.push(/* @__PURE__ */ jsx("span", {
38
- className: emphasized ? "bg-green-500/30 rounded-[2px]" : void 0,
40
+ className: emphasized ? "bg-(--theme-success)/30 rounded-[2px]" : void 0,
39
41
  style: t.color ? { color: t.color } : void 0,
40
42
  children: t.content.slice(start, end)
41
43
  }, key++));
@@ -65,7 +67,7 @@ function DiffRows({ rows, lang }) {
65
67
  return /* @__PURE__ */ jsx("div", {
66
68
  className: "overflow-x-auto rounded-md border theme-border font-mono text-xs leading-5",
67
69
  children: rows.map((row, i) => /* @__PURE__ */ jsxs("div", {
68
- className: cx("flex whitespace-pre", row.kind === "add" && "bg-green-500/15", row.kind === "del" && "bg-red-500/15", row.kind === "gap" && "theme-muted-text"),
70
+ className: cx("flex whitespace-pre", row.kind === "add" && "bg-(--theme-success)/15", row.kind === "del" && "bg-(--theme-error)/15", row.kind === "gap" && "theme-muted-text"),
69
71
  children: [
70
72
  numbered && /* @__PURE__ */ jsx("span", {
71
73
  className: "w-10 shrink-0 select-none text-right pr-2 theme-muted-text",
@@ -150,7 +152,7 @@ function ResultBody({ part }) {
150
152
  type: "button",
151
153
  onClick: () => setShowAll(true),
152
154
  className: "text-xs text-(--theme-link) hover:underline",
153
- children: t.moreLines.replace("{count}", String(hidden))
155
+ children: t.moreLines(hidden)
154
156
  }),
155
157
  showAll && lines.length > COLLAPSED_RESULT_LINES && /* @__PURE__ */ jsx("button", {
156
158
  type: "button",
@@ -161,20 +163,42 @@ function ResultBody({ part }) {
161
163
  ]
162
164
  });
163
165
  }
166
+ /** A status mark, which color alone tells apart, with its status in words for
167
+ * a screen reader. */
168
+ function StatusMark({ status, children }) {
169
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
170
+ "aria-hidden": "true",
171
+ className: "contents",
172
+ children
173
+ }), /* @__PURE__ */ jsx("span", {
174
+ className: "sr-only",
175
+ children: status
176
+ })] });
177
+ }
164
178
  function ToolStatusDot({ part }) {
165
- if (part.status === "running") return /* @__PURE__ */ jsx(Loader, {
166
- inline: true,
167
- decorative: true,
168
- size: 14,
169
- color: "var(--theme-muted-text-color)"
179
+ const t = useChatConfig().strings.agentTranscript;
180
+ if (part.status === "running") return /* @__PURE__ */ jsx(StatusMark, {
181
+ status: t.running,
182
+ children: /* @__PURE__ */ jsx(Loader, {
183
+ inline: true,
184
+ decorative: true,
185
+ size: 14,
186
+ color: "var(--theme-muted-text-color)"
187
+ })
170
188
  });
171
- if (part.status === "error") return /* @__PURE__ */ jsx("span", {
172
- className: "text-red-500 leading-none",
173
- children: "●"
189
+ if (part.status === "error") return /* @__PURE__ */ jsx(StatusMark, {
190
+ status: t.failed,
191
+ children: /* @__PURE__ */ jsx("span", {
192
+ className: "leading-none text-(--theme-error)",
193
+ children: "●"
194
+ })
174
195
  });
175
- return /* @__PURE__ */ jsx("span", {
176
- className: "text-green-600 leading-none",
177
- children: "●"
196
+ return /* @__PURE__ */ jsx(StatusMark, {
197
+ status: t.done,
198
+ children: /* @__PURE__ */ jsx("span", {
199
+ className: "leading-none text-(--theme-success)",
200
+ children: "●"
201
+ })
178
202
  });
179
203
  }
180
204
  /** A part's toggle row: its status mark and name, across the transcript's width. */
@@ -251,18 +275,21 @@ function SubagentCard({ part }) {
251
275
  onOpenChange: setExpanded,
252
276
  disabled: !canExpand,
253
277
  summaryClassName: rowSummaryClasses,
254
- summary: /* @__PURE__ */ jsxs(Fragment, { children: [part.status === "running" ? /* @__PURE__ */ jsx("span", {
255
- className: "mt-[3px]",
256
- children: /* @__PURE__ */ jsx(Loader, {
257
- inline: true,
258
- decorative: true,
259
- size: 14,
260
- color: "var(--theme-muted-text-color)"
278
+ summary: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(StatusMark, {
279
+ status: part.status === "running" ? t.running : part.status === "failed" ? t.failed : t.done,
280
+ children: part.status === "running" ? /* @__PURE__ */ jsx("span", {
281
+ className: "mt-[3px]",
282
+ children: /* @__PURE__ */ jsx(Loader, {
283
+ inline: true,
284
+ decorative: true,
285
+ size: 14,
286
+ color: "var(--theme-muted-text-color)"
287
+ })
288
+ }) : /* @__PURE__ */ jsx("span", {
289
+ className: cx("leading-none", part.status === "failed" ? "text-(--theme-error)" : "text-(--theme-success)"),
290
+ style: color && part.status !== "failed" ? { color } : void 0,
291
+ children: "●"
261
292
  })
262
- }) : /* @__PURE__ */ jsx("span", {
263
- className: cx("leading-none", part.status === "failed" ? "text-(--theme-error)" : "text-(--theme-success)"),
264
- style: color && part.status !== "failed" ? { color } : void 0,
265
- children: "●"
266
293
  }), /* @__PURE__ */ jsxs("span", {
267
294
  className: "font-mono text-[13px] leading-5 min-w-0 truncate",
268
295
  children: [/* @__PURE__ */ jsx("span", {
@@ -343,7 +370,7 @@ function ConfirmApproval({ part, onAnswer }) {
343
370
  kind: "confirm",
344
371
  allowed: false
345
372
  }),
346
- className: "px-3 py-1 text-xs font-medium rounded-full border theme-border hover:theme-hover text-red-600",
373
+ className: "px-3 py-1 text-xs font-medium rounded-full border theme-border hover:theme-hover text-(--theme-error-text)",
347
374
  children: denyLabel
348
375
  }),
349
376
  /* @__PURE__ */ jsx("button", {
@@ -353,21 +380,26 @@ function ConfirmApproval({ part, onAnswer }) {
353
380
  children: t.denyWithFeedback
354
381
  })
355
382
  ]
356
- }) : /* @__PURE__ */ jsxs("div", {
383
+ }) : /* @__PURE__ */ jsxs("form", {
357
384
  className: "flex gap-2",
385
+ onSubmit: (e) => {
386
+ e.preventDefault();
387
+ if (feedback.trim()) answer({
388
+ kind: "confirm",
389
+ allowed: false,
390
+ denyMessage: feedback.trim()
391
+ });
392
+ },
358
393
  children: [/* @__PURE__ */ jsx("input", {
394
+ ref: focusOnMount,
359
395
  value: feedback,
360
396
  onChange: (e) => setFeedback(e.target.value),
397
+ "aria-label": t.feedbackLabel,
361
398
  placeholder: t.feedbackPlaceholder,
362
399
  className: cx(fieldBox({ size: "sm" }), "flex-1")
363
400
  }), /* @__PURE__ */ jsx("button", {
364
- type: "button",
401
+ type: "submit",
365
402
  disabled: !feedback.trim(),
366
- onClick: () => answer({
367
- kind: "confirm",
368
- allowed: false,
369
- denyMessage: feedback.trim()
370
- }),
371
403
  className: "px-3 py-1 text-xs font-medium rounded-full bg-(--theme-accent) text-(--theme-accent-text) disabled:opacity-50",
372
404
  children: common.send
373
405
  })]
@@ -417,16 +449,22 @@ function AskApproval({ part, onAnswer }) {
417
449
  className: "px-3 py-1 text-xs rounded-full theme-muted-text hover:theme-hover",
418
450
  children: t.writeOwnAnswer
419
451
  })]
420
- }) : /* @__PURE__ */ jsxs("div", {
452
+ }) : /* @__PURE__ */ jsxs("form", {
421
453
  className: "flex gap-2",
454
+ onSubmit: (e) => {
455
+ e.preventDefault();
456
+ if (own.trim()) answer(own.trim());
457
+ },
422
458
  children: [/* @__PURE__ */ jsx("input", {
459
+ ref: focusOnMount,
423
460
  value: own,
424
461
  onChange: (e) => setOwn(e.target.value),
462
+ "aria-label": t.ownAnswerLabel,
463
+ placeholder: t.ownAnswerLabel,
425
464
  className: cx(fieldBox({ size: "sm" }), "flex-1")
426
465
  }), /* @__PURE__ */ jsx("button", {
427
- type: "button",
466
+ type: "submit",
428
467
  disabled: !own.trim(),
429
- onClick: () => answer(own.trim()),
430
468
  className: "px-3 py-1 text-xs font-medium rounded-full bg-(--theme-accent) text-(--theme-accent-text) disabled:opacity-50",
431
469
  children: common.send
432
470
  })]
@@ -435,6 +473,8 @@ function AskApproval({ part, onAnswer }) {
435
473
  function ApprovalBlock({ part, onApprovalAnswer }) {
436
474
  const { strings } = useChatConfig();
437
475
  const t = strings.agentTranscript;
476
+ const headingId = useId();
477
+ const heading = part.header ?? part.toolName;
438
478
  if (part.resolved) return /* @__PURE__ */ jsxs("div", {
439
479
  className: "my-1.5 rounded-lg border theme-border p-2.5 text-xs theme-muted-text space-y-1",
440
480
  "data-testid": "approval-part",
@@ -446,12 +486,15 @@ function ApprovalBlock({ part, onApprovalAnswer }) {
446
486
  children: [/* @__PURE__ */ jsx(CheckIcon, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ jsxs("span", { children: [t.answered, part.answer ? `: ${part.answer}` : ""] })]
447
487
  })]
448
488
  });
449
- return /* @__PURE__ */ jsxs("div", {
450
- className: "my-1.5 rounded-lg border border-(--theme-accent) p-3 space-y-2",
489
+ return /* @__PURE__ */ jsxs("fieldset", {
490
+ "aria-labelledby": heading ? headingId : void 0,
491
+ "aria-label": heading ? void 0 : t.approvalLabel,
492
+ className: "my-1.5 min-w-0 rounded-lg border border-(--theme-accent) p-3 space-y-2",
451
493
  "data-testid": "approval-part",
452
- children: [(part.header || part.toolName) && /* @__PURE__ */ jsx("div", {
494
+ children: [heading && /* @__PURE__ */ jsx("div", {
495
+ id: headingId,
453
496
  className: "text-xs font-semibold",
454
- children: part.header ?? part.toolName
497
+ children: heading
455
498
  }), part.approvalKind === "confirm" ? /* @__PURE__ */ jsx(ConfirmApproval, {
456
499
  part,
457
500
  onAnswer: onApprovalAnswer
@@ -488,10 +531,18 @@ function TodoSnapshotBlock({ part }) {
488
531
  className: "space-y-0.5 text-sm",
489
532
  children: part.todos.map((todo) => /* @__PURE__ */ jsxs("li", {
490
533
  className: cx("flex items-start gap-2", todo.status === "completed" && "line-through theme-muted-text", todo.status === "in_progress" && "font-semibold"),
491
- children: [/* @__PURE__ */ jsx("span", {
492
- className: "select-none font-mono",
493
- children: todo.status === "completed" ? "✔" : todo.status === "in_progress" ? "■" : "□"
494
- }), /* @__PURE__ */ jsx("span", { children: todo.status === "in_progress" && todo.activeForm ? todo.activeForm : todo.content })]
534
+ children: [
535
+ /* @__PURE__ */ jsx("span", {
536
+ "aria-hidden": "true",
537
+ className: "select-none font-mono",
538
+ children: todo.status === "completed" ? "✔" : todo.status === "in_progress" ? "■" : "□"
539
+ }),
540
+ /* @__PURE__ */ jsx("span", {
541
+ className: "sr-only",
542
+ children: todo.status === "completed" ? t.todoCompleted : todo.status === "in_progress" ? t.todoInProgress : t.todoPending
543
+ }),
544
+ /* @__PURE__ */ jsx("span", { children: todo.status === "in_progress" && todo.activeForm ? todo.activeForm : todo.content })
545
+ ]
495
546
  }, todo.content))
496
547
  })]
497
548
  });
@@ -518,7 +569,7 @@ function NoticeBlock({ part }) {
518
569
  });
519
570
  }
520
571
  return /* @__PURE__ */ jsx("div", {
521
- className: cx("my-1 text-xs rounded-md px-2.5 py-1.5", part.kind === "error" ? "bg-red-500/10 text-red-700" : "bg-yellow-500/10 text-yellow-700"),
572
+ className: cx("my-1 text-xs rounded-md border px-2.5 py-1.5", toneSurface[part.kind === "error" ? "error" : "warning"]),
522
573
  "data-testid": `${part.kind}-part`,
523
574
  children: part.text
524
575
  });
@@ -526,7 +577,7 @@ function NoticeBlock({ part }) {
526
577
  /** The TUI's thought, drawn like a chat reply's: while it streams its label
527
578
  * shimmers over the latest lines, then it folds to the label and opens in
528
579
  * place on request. */
529
- function ReasoningBlock({ part, isStreaming }) {
580
+ var ReasoningBlock = memo(function ReasoningBlock({ part, isStreaming }) {
530
581
  const { strings } = useChatConfig();
531
582
  const t = strings.thinking;
532
583
  const [expanded, setExpanded] = useState(false);
@@ -569,7 +620,7 @@ function ReasoningBlock({ part, isStreaming }) {
569
620
  })
570
621
  })
571
622
  });
572
- }
623
+ });
573
624
  function TextBlock({ part, isStreaming }) {
574
625
  return /* @__PURE__ */ jsx("div", {
575
626
  className: cx(chatProseClasses, "[&:not(:first-child)]:mt-4"),
@@ -583,21 +634,30 @@ function PartDispatch(props) {
583
634
  const { slots } = useChatConfig();
584
635
  const Override = slots.partRenderers?.[props.part.kind];
585
636
  if (Override) return /* @__PURE__ */ jsx(Override, { ...props });
586
- const { part } = props;
637
+ return /* @__PURE__ */ jsx(BuiltinPart, {
638
+ part: props.part,
639
+ isStreaming: props.isStreaming ?? false,
640
+ onApprovalAnswer: props.onApprovalAnswer
641
+ });
642
+ }
643
+ /** The package's own drawing of a part. Memoized on the part itself, which
644
+ * keeps its identity until a delta changes it, so a streamed token re-renders
645
+ * only the part it lands in, not every finished call and answer before it. */
646
+ var BuiltinPart = memo(function BuiltinPart({ part, isStreaming, onApprovalAnswer }) {
587
647
  switch (part.kind) {
588
648
  case "text": return /* @__PURE__ */ jsx(TextBlock, {
589
649
  part,
590
- isStreaming: props.isStreaming ?? false
650
+ isStreaming
591
651
  });
592
652
  case "reasoning": return /* @__PURE__ */ jsx(ReasoningBlock, {
593
653
  part,
594
- isStreaming: props.isStreaming ?? false
654
+ isStreaming
595
655
  });
596
656
  case "tool_call": return /* @__PURE__ */ jsx(ToolCallBlock, { part });
597
657
  case "subagent": return /* @__PURE__ */ jsx(SubagentCard, { part });
598
658
  case "approval": return /* @__PURE__ */ jsx(ApprovalBlock, {
599
659
  part,
600
- onApprovalAnswer: props.onApprovalAnswer
660
+ onApprovalAnswer
601
661
  });
602
662
  case "notice":
603
663
  case "warning":
@@ -605,13 +665,14 @@ function PartDispatch(props) {
605
665
  case "todo_snapshot": return /* @__PURE__ */ jsx(TodoSnapshotBlock, { part });
606
666
  default: return null;
607
667
  }
608
- }
668
+ });
609
669
  function isReasoning(m) {
610
670
  return m.part.kind === "reasoning";
611
671
  }
612
672
  /** Two thoughts with nothing visible between them read as one, not as a
613
673
  * stack of identical lines. */
614
674
  function mergeReasoning(parts) {
675
+ if (parts.length === 1 && parts[0]) return parts[0];
615
676
  const durationMs = parts.reduce((sum, p) => sum + (p.durationMs ?? 0), 0);
616
677
  return {
617
678
  kind: "reasoning",
@@ -23,11 +23,6 @@ interface ChatContextValue {
23
23
  hasLoadedModels: boolean;
24
24
  modelsError: string | null;
25
25
  isStreaming: boolean;
26
- isThinking: boolean;
27
- streamingContent: string;
28
- streamingReasoning: string;
29
- streamingParts: MessagePart[];
30
- thinkingStartTime: number | null;
31
26
  sidebar: SidebarState;
32
27
  /** True unless the sidebar is expanded. */
33
28
  sidebarCollapsed: boolean;
@@ -57,12 +52,28 @@ interface ChatContextValue {
57
52
  navigateToBranch: (messageId: string) => void;
58
53
  clearCurrentConversation: () => void;
59
54
  }
55
+ /** The reply being written, which changes with every streamed token. It has
56
+ * its own context so that only what draws the reply re-renders per token,
57
+ * not the composer, the conversation list and every other `useChat` reader. */
58
+ export interface ChatStream {
59
+ /** True while the model is reasoning, before its answer starts. */
60
+ isThinking: boolean;
61
+ streamingContent: string;
62
+ streamingReasoning: string;
63
+ streamingParts: MessagePart[];
64
+ thinkingStartTime: number | null;
65
+ }
60
66
  export declare function useChat(): ChatContextValue;
67
+ /** The reply being streamed. A component that reads it re-renders on every
68
+ * token, so read it only where the reply is drawn. */
69
+ export declare function useChatStream(): ChatStream;
61
70
  export interface ChatProviderProps {
62
71
  adapter: ChatAdapter;
63
72
  currentUser: ChatUser;
64
73
  navigation: ChatNavigation;
65
74
  activeConversationId?: string | null;
75
+ /** Resolved once per object: keep it stable (a module constant or a
76
+ * `useMemo`), or every reader of the config re-renders with the provider. */
66
77
  config?: ChatUIConfig;
67
78
  /** Owns the sidebar's state. Omit to leave it to the reader, remembered
68
79
  * per browser. */
@@ -45,11 +45,19 @@ function heldSendArgs(held) {
45
45
  ];
46
46
  }
47
47
  var ChatContext = createContext(void 0);
48
+ var ChatStreamContext = createContext(void 0);
48
49
  function useChat() {
49
50
  const context = useContext(ChatContext);
50
51
  if (!context) throw new Error("useChat must be used within a ChatProvider");
51
52
  return context;
52
53
  }
54
+ /** The reply being streamed. A component that reads it re-renders on every
55
+ * token, so read it only where the reply is drawn. */
56
+ function useChatStream() {
57
+ const context = useContext(ChatStreamContext);
58
+ if (!context) throw new Error("useChatStream must be used within a ChatProvider");
59
+ return context;
60
+ }
53
61
  function ChatProvider({ adapter, currentUser, navigation, activeConversationId = null, config, sidebar: sidebarProp, onSidebarChange, drawerOpen: drawerOpenProp, onDrawerOpenChange, children }) {
54
62
  const [state, dispatch] = useReducer(chatReducer, initialState);
55
63
  const hasLoadedConversationsRef = useRef(false);
@@ -750,11 +758,6 @@ function ChatProvider({ adapter, currentUser, navigation, activeConversationId =
750
758
  hasLoadedModels: state.hasLoadedModels,
751
759
  modelsError: state.modelsError,
752
760
  isStreaming: state.isStreaming,
753
- isThinking: state.isThinking,
754
- streamingContent: state.streamingContent,
755
- streamingReasoning: state.streamingReasoning,
756
- streamingParts: state.streamingParts,
757
- thinkingStartTime: state.thinkingStartTime,
758
761
  sidebar,
759
762
  sidebarCollapsed: sidebar !== "expanded",
760
763
  sidebarPresentation,
@@ -785,7 +788,21 @@ function ChatProvider({ adapter, currentUser, navigation, activeConversationId =
785
788
  currentUser,
786
789
  navigation,
787
790
  activeConversationId,
788
- state,
791
+ state.conversations,
792
+ state.currentConversation,
793
+ state.providers,
794
+ state.models,
795
+ state.unreachableSessions,
796
+ state.providerIssues,
797
+ state.selectedProvider,
798
+ state.selectedAllocation,
799
+ state.isLoading,
800
+ state.isLoadingConversation,
801
+ state.isLoadingModels,
802
+ state.hasLoadedModels,
803
+ state.modelsError,
804
+ state.isStreaming,
805
+ state.queuedMessages,
789
806
  sidebar,
790
807
  sidebarPresentation,
791
808
  drawerOpen,
@@ -811,16 +828,32 @@ function ChatProvider({ adapter, currentUser, navigation, activeConversationId =
811
828
  navigateToBranch,
812
829
  clearCurrentConversation
813
830
  ]);
831
+ const stream = useMemo(() => ({
832
+ isThinking: state.isThinking,
833
+ streamingContent: state.streamingContent,
834
+ streamingReasoning: state.streamingReasoning,
835
+ streamingParts: state.streamingParts,
836
+ thinkingStartTime: state.thinkingStartTime
837
+ }), [
838
+ state.isThinking,
839
+ state.streamingContent,
840
+ state.streamingReasoning,
841
+ state.streamingParts,
842
+ state.thinkingStartTime
843
+ ]);
814
844
  return /* @__PURE__ */ jsx(ChatConfigProvider, {
815
845
  value: resolvedConfig,
816
846
  children: /* @__PURE__ */ jsx(ReportSidebarPresentationContext.Provider, {
817
847
  value: reportSidebarPresentation,
818
848
  children: /* @__PURE__ */ jsx(ChatContext.Provider, {
819
849
  value,
820
- children
850
+ children: /* @__PURE__ */ jsx(ChatStreamContext.Provider, {
851
+ value: stream,
852
+ children
853
+ })
821
854
  })
822
855
  })
823
856
  });
824
857
  }
825
858
  //#endregion
826
- export { ChatProvider, useChat };
859
+ export { ChatProvider, useChat, useChatStream };
@@ -1,4 +1,4 @@
1
- import { safeUrl } from "../../safeUrl.js";
1
+ import { AppLink } from "../../components/AppLink.js";
2
2
  import { defaultChatStrings } from "../strings.js";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  import { createContext, useContext } from "react";
@@ -6,13 +6,14 @@ import { createContext, useContext } from "react";
6
6
  function hrefFor(target) {
7
7
  switch (target.kind) {
8
8
  case "conversation": return `/chat/${target.id}`;
9
+ case "newChat": return "/chat";
9
10
  case "attachments": return "/chat/attachments";
10
11
  case "external": return target.href;
11
12
  }
12
13
  }
13
14
  function DefaultLink({ target, className, title, onClick, children }) {
14
- return /* @__PURE__ */ jsx("a", {
15
- href: safeUrl(hrefFor(target)),
15
+ return /* @__PURE__ */ jsx(AppLink, {
16
+ href: hrefFor(target),
16
17
  className,
17
18
  title,
18
19
  onClick,
@@ -24,7 +24,7 @@ export { default as ProviderIssueBanner } from './components/ProviderIssueBanner
24
24
  export { default as ShareDialog, ShareButton, } from './components/ShareDialog.js';
25
25
  export { type SlashCommandOption, type SlashMenuConfig, slashMatches, } from './components/SlashMenu.js';
26
26
  export type { ComposerPastes, PasteUploadResult, } from './components/usePasteCards.js';
27
- export { ChatProvider, type ChatProviderProps, useChat, } from './core/ChatProvider.js';
27
+ export { ChatProvider, type ChatProviderProps, type ChatStream, useChat, useChatStream, } from './core/ChatProvider.js';
28
28
  export { type ChatAction, type ChatState, chatReducer, initialState, } from './core/chatReducer.js';
29
29
  export type { PartRendererProps } from './core/config.js';
30
30
  export { type ChatLinkProps, type ChatUIConfig, resolveChatConfig, useChatConfig, } from './core/config.js';
package/dist/ai/index.js CHANGED
@@ -11,7 +11,7 @@ import { chatReducer, initialState } from "./core/chatReducer.js";
11
11
  import { defaultChatStrings } from "./strings.js";
12
12
  import { resolveChatConfig, useChatConfig } from "./core/config.js";
13
13
  import { providerIssueFor } from "./core/providerIssues.js";
14
- import { ChatProvider, useChat } from "./core/ChatProvider.js";
14
+ import { ChatProvider, useChat, useChatStream } from "./core/ChatProvider.js";
15
15
  import { isMac, isOrgModel } from "./utils.js";
16
16
  import AllocationSelector from "./components/AllocationSelector.js";
17
17
  import AttachmentManager from "./components/AttachmentManager.js";
@@ -24,7 +24,6 @@ import BlockedGroupBanner from "./components/BlockedGroupBanner.js";
24
24
  import BranchNavigator from "./components/BranchNavigator.js";
25
25
  import { getGreeting } from "./core/greeting.js";
26
26
  import useDragDrop from "./core/useDragDrop.js";
27
- import { NoticeBar, NoticeCard, OutputCard } from "./ui/Notice.js";
28
27
  import { ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ManageProvidersLink } from "./components/ComposerChrome.js";
29
28
  import DragOverlay from "./components/DragOverlay.js";
30
29
  import { pasteInlineMaxBytes } from "./core/pastes.js";
@@ -45,4 +44,5 @@ import ChatLayout, { CHAT_COLUMN_SCOPE, ConversationLayout, DRAWER_BELOW_PX } fr
45
44
  import ChatMessage_default from "./components/ChatMessage.js";
46
45
  import ChatMessageList from "./components/ChatMessageList.js";
47
46
  import ChatThread from "./components/ChatThread.js";
48
- export { AGENT_COLOR_NAMES, ActivityLine, AgentMessageParts, AllocationSelector, ApprovalBlock, AttachmentManager, AttachmentUpload, BlockedGroupBanner, BranchNavigator, CHAT_COLUMN_SCOPE, ChatAdapterError, ChatEmptyState, ChatInput, ChatLayout, ChatMessageList, ChatMessage_default as ChatMessageView, ChatProvider, ChatSidebar, ChatStage, ChatThread, ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ConversationLayout, ConversationSidebar, DEFAULT_PERMISSION_MODE, DRAWER_BELOW_PX, DragOverlay, FOCUS_SIDEBAR_SEARCH_EVENT, INTERRUPTED_NOTICE, KeyboardShortcutsProvider, MAX_EDIT_DIFF_LINES, MAX_WRITE_DIFF_LINES, ManageProvidersLink, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, ShareButton, ShareDialog, SidebarGroupHeading, SidebarPanel, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, computeEditDiff, computeWriteRows, defaultChatStrings, defaultToolStrings, editSummary, finalizeParts, firstNonEmptyLine, fullToolArgs, getGreeting, getProviderKeyFromModelId, groupConversationsByDate, hiddenTranscriptTool, initialState, interruptionNotice, isEditDiffTool, isGroupableTool, isMac, isNamedPermissionMode, isOrgModel, languageForPath, lineDelta, parseEditArgs, parseSubagentNotice, pasteInlineMaxBytes, permissionModesUpTo, planFromArgs, providerIssueFor, resolveChatConfig, resultFailed, rollupSentence, sanitizeLabel, sanitizePanelText, sidebarDrawerProps, slashMatches, subagentDeliveryLine, summarizeToolArgs, taskCallFromArgs, thinkingHeading, tokenizeDiffLines, toolHeaderFor, toolSummary, useChat, useChatConfig, useConversationActions, useDragDrop, useKeyboardShortcuts, useRowDialogs, wordEmphasisRanges };
47
+ import { NoticeBar, NoticeCard, OutputCard } from "./ui/Notice.js";
48
+ export { AGENT_COLOR_NAMES, ActivityLine, AgentMessageParts, AllocationSelector, ApprovalBlock, AttachmentManager, AttachmentUpload, BlockedGroupBanner, BranchNavigator, CHAT_COLUMN_SCOPE, ChatAdapterError, ChatEmptyState, ChatInput, ChatLayout, ChatMessageList, ChatMessage_default as ChatMessageView, ChatProvider, ChatSidebar, ChatStage, ChatThread, ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ConversationLayout, ConversationSidebar, DEFAULT_PERMISSION_MODE, DRAWER_BELOW_PX, DragOverlay, FOCUS_SIDEBAR_SEARCH_EVENT, INTERRUPTED_NOTICE, KeyboardShortcutsProvider, MAX_EDIT_DIFF_LINES, MAX_WRITE_DIFF_LINES, ManageProvidersLink, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, ShareButton, ShareDialog, SidebarGroupHeading, SidebarPanel, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, computeEditDiff, computeWriteRows, defaultChatStrings, defaultToolStrings, editSummary, finalizeParts, firstNonEmptyLine, fullToolArgs, getGreeting, getProviderKeyFromModelId, groupConversationsByDate, hiddenTranscriptTool, initialState, interruptionNotice, isEditDiffTool, isGroupableTool, isMac, isNamedPermissionMode, isOrgModel, languageForPath, lineDelta, parseEditArgs, parseSubagentNotice, pasteInlineMaxBytes, permissionModesUpTo, planFromArgs, providerIssueFor, resolveChatConfig, resultFailed, rollupSentence, sanitizeLabel, sanitizePanelText, sidebarDrawerProps, slashMatches, subagentDeliveryLine, summarizeToolArgs, taskCallFromArgs, thinkingHeading, tokenizeDiffLines, toolHeaderFor, toolSummary, useChat, useChatConfig, useChatStream, useConversationActions, useDragDrop, useKeyboardShortcuts, useRowDialogs, wordEmphasisRanges };
@@ -17,7 +17,7 @@ export interface ChatStrings {
17
17
  shareButton: string;
18
18
  };
19
19
  blockedGroup: {
20
- title: string;
20
+ title: (group: string) => string;
21
21
  message: string;
22
22
  };
23
23
  providerIssue: {
@@ -64,6 +64,8 @@ export interface ChatStrings {
64
64
  activity: {
65
65
  tokens: (input: string, output: string) => string;
66
66
  stop: string;
67
+ /** The status words an agent's working line picks from, one per turn. */
68
+ words: readonly string[];
67
69
  };
68
70
  emptyState: {
69
71
  greeting: string | null;
@@ -101,6 +103,8 @@ export interface ChatStrings {
101
103
  };
102
104
  thread: {
103
105
  viewOnly: string;
106
+ /** Names the thread, a live log of the conversation, for assistive technology. */
107
+ label: string;
104
108
  };
105
109
  sidebar: {
106
110
  groupToday: string;
@@ -139,6 +143,16 @@ export interface ChatStrings {
139
143
  attachmentManager: {
140
144
  title: string;
141
145
  empty: string;
146
+ /** Names an image attachment that has no file name. */
147
+ unnamedImage: string;
148
+ /** Names a file attachment that has no file name. */
149
+ unnamedFile: string;
150
+ /** Opens an attachment's preview, given its name. */
151
+ open: (name: string) => string;
152
+ /** Names an attachment's download link, given its name. */
153
+ download: (name: string) => string;
154
+ /** Names an attachment's delete button, given its name. */
155
+ remove: (name: string) => string;
142
156
  };
143
157
  branch: {
144
158
  previous: string;
@@ -157,7 +171,8 @@ export interface ChatStrings {
157
171
  stopped: string;
158
172
  tokens: (total: number) => string;
159
173
  tokensBreakdown: (prompt: number, completion: number) => string;
160
- copy: string;
174
+ /** What a message's copy button names: "Copy message", then "Copied message". */
175
+ copyLabel: string;
161
176
  edit: string;
162
177
  regenerate: string;
163
178
  editPlaceholder: string;
@@ -182,7 +197,8 @@ export interface ChatStrings {
182
197
  interrupted: string;
183
198
  noOutput: string;
184
199
  diffTruncated: string;
185
- moreLines: string;
200
+ /** Under a long tool result, how many of its lines are folded away. */
201
+ moreLines: (count: number) => string;
186
202
  allowOnce: string;
187
203
  allowDirectory: string;
188
204
  deny: string;
@@ -201,6 +217,16 @@ export interface ChatStrings {
201
217
  planPending: string;
202
218
  approvalPending: string;
203
219
  approvalOptions: string;
220
+ /** Names a question the agent waits on that has no heading of its own. */
221
+ approvalLabel: string;
222
+ /** Names the field for the reason a request is denied. */
223
+ feedbackLabel: string;
224
+ /** Names the field for an answer of the reader's own. */
225
+ ownAnswerLabel: string;
226
+ /** Read out in place of a task's checkbox glyph. */
227
+ todoPending: string;
228
+ todoInProgress: string;
229
+ todoCompleted: string;
204
230
  };
205
231
  /** One-line summaries of an agent's finished tool calls. */
206
232
  tools: ToolStrings;