@artooi/ag-ui-web-component 0.36.0 → 0.38.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 (199) hide show
  1. package/CHANGELOG.md +140 -1
  2. package/README.md +9 -5
  3. package/dist/ag-ui-web-component.bundle.js +81 -81
  4. package/dist/ag-ui-web-component.bundle.js.map +4 -4
  5. package/dist/core/activity_registration.d.ts +19 -0
  6. package/dist/core/activity_registration.d.ts.map +1 -0
  7. package/dist/core/activity_renderer.d.ts +20 -0
  8. package/dist/core/activity_renderer.d.ts.map +1 -0
  9. package/dist/core/ag_ui_chat.d.ts +6 -126
  10. package/dist/core/ag_ui_chat.d.ts.map +1 -1
  11. package/dist/core/events/attachments_detail.d.ts +9 -0
  12. package/dist/core/events/attachments_detail.d.ts.map +1 -0
  13. package/dist/core/events/custom_agent_detail.d.ts +8 -0
  14. package/dist/core/events/custom_agent_detail.d.ts.map +1 -0
  15. package/dist/core/events/feedback_detail.d.ts +7 -0
  16. package/dist/core/events/feedback_detail.d.ts.map +1 -0
  17. package/dist/core/events/invalidate_detail.d.ts +16 -0
  18. package/dist/core/events/invalidate_detail.d.ts.map +1 -0
  19. package/dist/core/events/run_finished_detail.d.ts +22 -0
  20. package/dist/core/events/run_finished_detail.d.ts.map +1 -0
  21. package/dist/core/events/state_detail.d.ts +5 -0
  22. package/dist/core/events/state_detail.d.ts.map +1 -0
  23. package/dist/core/events/submit_detail.d.ts +8 -0
  24. package/dist/core/events/submit_detail.d.ts.map +1 -0
  25. package/dist/core/events/toggle_detail.d.ts +5 -0
  26. package/dist/core/events/toggle_detail.d.ts.map +1 -0
  27. package/dist/core/events/tool_run.d.ts +11 -0
  28. package/dist/core/events/tool_run.d.ts.map +1 -0
  29. package/dist/core/events/unread_detail.d.ts +5 -0
  30. package/dist/core/events/unread_detail.d.ts.map +1 -0
  31. package/dist/core/message_role.d.ts +4 -0
  32. package/dist/core/message_role.d.ts.map +1 -0
  33. package/dist/core/tool_outcome.d.ts +1 -1
  34. package/dist/core/tool_outcome.d.ts.map +1 -1
  35. package/dist/index.d.ts +30 -17
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +6242 -6178
  38. package/dist/index.js.map +4 -4
  39. package/dist/ui/charts/chart_block.d.ts.map +1 -0
  40. package/dist/ui/charts/chart_spec_from.d.ts.map +1 -0
  41. package/dist/ui/{chart_tool.d.ts → charts/chart_tool.d.ts} +1 -1
  42. package/dist/ui/charts/chart_tool.d.ts.map +1 -0
  43. package/dist/ui/{attachment_tray.d.ts → composer/attachment_tray.d.ts} +3 -3
  44. package/dist/ui/composer/attachment_tray.d.ts.map +1 -0
  45. package/dist/ui/{skills_menu.d.ts → composer/skills_menu.d.ts} +1 -1
  46. package/dist/ui/composer/skills_menu.d.ts.map +1 -0
  47. package/dist/ui/{voice_input.d.ts → composer/voice_input.d.ts} +2 -2
  48. package/dist/ui/composer/voice_input.d.ts.map +1 -0
  49. package/dist/ui/{attach_copy_buttons.d.ts → excerpts/attach_copy_buttons.d.ts} +1 -1
  50. package/dist/ui/excerpts/attach_copy_buttons.d.ts.map +1 -0
  51. package/dist/ui/excerpts/copy_payload.d.ts.map +1 -0
  52. package/dist/ui/excerpts/page_quote_offer.d.ts.map +1 -0
  53. package/dist/ui/excerpts/quote_selection.d.ts.map +1 -0
  54. package/dist/ui/{checkpoint_menu.d.ts → history/checkpoint_menu.d.ts} +2 -2
  55. package/dist/ui/history/checkpoint_menu.d.ts.map +1 -0
  56. package/dist/ui/{relative_time.d.ts → history/relative_time.d.ts} +1 -1
  57. package/dist/ui/history/relative_time.d.ts.map +1 -0
  58. package/dist/ui/{thread_drawer.d.ts → history/thread_drawer.d.ts} +2 -2
  59. package/dist/ui/history/thread_drawer.d.ts.map +1 -0
  60. package/dist/ui/{approval_card.d.ts → interrupts/approval_card.d.ts} +1 -1
  61. package/dist/ui/interrupts/approval_card.d.ts.map +1 -0
  62. package/dist/ui/{confirmation_card.d.ts → interrupts/confirmation_card.d.ts} +1 -1
  63. package/dist/ui/interrupts/confirmation_card.d.ts.map +1 -0
  64. package/dist/ui/{question_card.d.ts → interrupts/question_card.d.ts} +1 -1
  65. package/dist/ui/interrupts/question_card.d.ts.map +1 -0
  66. package/dist/ui/placement/clamp_launcher.d.ts.map +1 -0
  67. package/dist/ui/placement/clamp_panel.d.ts.map +1 -0
  68. package/dist/ui/placement/launcher_drag.d.ts.map +1 -0
  69. package/dist/ui/placement/launcher_placement.d.ts.map +1 -0
  70. package/dist/ui/placement/panel_drag.d.ts.map +1 -0
  71. package/dist/ui/placement/place_widget.d.ts.map +1 -0
  72. package/dist/ui/placement/resize_handle.d.ts.map +1 -0
  73. package/dist/ui/progress/prettify_tool_name.d.ts.map +1 -0
  74. package/dist/ui/progress/run_notice.d.ts.map +1 -0
  75. package/dist/ui/{subagent_panel.d.ts → progress/subagent_panel.d.ts} +2 -2
  76. package/dist/ui/progress/subagent_panel.d.ts.map +1 -0
  77. package/dist/ui/progress/subagent_update.d.ts.map +1 -0
  78. package/dist/ui/{thoughts_block.d.ts → progress/thoughts_block.d.ts} +1 -1
  79. package/dist/ui/progress/thoughts_block.d.ts.map +1 -0
  80. package/dist/ui/{tool_call_card.d.ts → progress/tool_call_card.d.ts} +2 -2
  81. package/dist/ui/progress/tool_call_card.d.ts.map +1 -0
  82. package/dist/ui/{attachment_chips.d.ts → transcript/attachment_chips.d.ts} +1 -1
  83. package/dist/ui/transcript/attachment_chips.d.ts.map +1 -0
  84. package/dist/ui/{message_actions.d.ts → transcript/message_actions.d.ts} +1 -1
  85. package/dist/ui/transcript/message_actions.d.ts.map +1 -0
  86. package/dist/ui/transcript/render_markdown.d.ts.map +1 -0
  87. package/dist/ui/transcript/reveal_words.d.ts.map +1 -0
  88. package/dist/ui/transcript/stick_to_bottom.d.ts.map +1 -0
  89. package/dist/ui/{suggestion_chips.d.ts → transcript/suggestion_chips.d.ts} +1 -1
  90. package/dist/ui/transcript/suggestion_chips.d.ts.map +1 -0
  91. package/dist/ui/ui_strings.d.ts +4 -0
  92. package/dist/ui/ui_strings.d.ts.map +1 -1
  93. package/package.json +5 -5
  94. package/src/core/activity_registration.ts +19 -0
  95. package/src/core/activity_renderer.ts +19 -0
  96. package/src/core/ag_ui_chat.ts +202 -211
  97. package/src/core/events/attachments_detail.ts +9 -0
  98. package/src/core/events/custom_agent_detail.ts +7 -0
  99. package/src/core/events/feedback_detail.ts +6 -0
  100. package/src/core/events/invalidate_detail.ts +15 -0
  101. package/src/core/events/run_finished_detail.ts +22 -0
  102. package/src/core/events/state_detail.ts +4 -0
  103. package/src/core/events/submit_detail.ts +8 -0
  104. package/src/core/events/toggle_detail.ts +4 -0
  105. package/src/core/events/tool_run.ts +10 -0
  106. package/src/core/events/unread_detail.ts +4 -0
  107. package/src/core/message_role.ts +4 -0
  108. package/src/core/tool_outcome.ts +1 -1
  109. package/src/index.ts +52 -54
  110. package/src/ui/{chart_tool.ts → charts/chart_tool.ts} +1 -1
  111. package/src/ui/{attachment_tray.ts → composer/attachment_tray.ts} +5 -5
  112. package/src/ui/{skills_menu.ts → composer/skills_menu.ts} +1 -1
  113. package/src/ui/{voice_input.ts → composer/voice_input.ts} +3 -3
  114. package/src/ui/{attach_copy_buttons.ts → excerpts/attach_copy_buttons.ts} +1 -1
  115. package/src/ui/{checkpoint_menu.ts → history/checkpoint_menu.ts} +2 -2
  116. package/src/ui/{relative_time.ts → history/relative_time.ts} +1 -1
  117. package/src/ui/{thread_drawer.ts → history/thread_drawer.ts} +2 -2
  118. package/src/ui/{approval_card.ts → interrupts/approval_card.ts} +1 -1
  119. package/src/ui/{confirmation_card.ts → interrupts/confirmation_card.ts} +1 -1
  120. package/src/ui/{question_card.ts → interrupts/question_card.ts} +1 -1
  121. package/src/ui/{clamp_launcher.ts → placement/clamp_launcher.ts} +1 -1
  122. package/src/ui/{clamp_panel.ts → placement/clamp_panel.ts} +1 -1
  123. package/src/ui/{launcher_placement.ts → placement/launcher_placement.ts} +1 -1
  124. package/src/ui/{subagent_panel.ts → progress/subagent_panel.ts} +2 -2
  125. package/src/ui/{subagent_update.ts → progress/subagent_update.ts} +1 -1
  126. package/src/ui/{thoughts_block.ts → progress/thoughts_block.ts} +1 -1
  127. package/src/ui/{tool_call_card.ts → progress/tool_call_card.ts} +2 -2
  128. package/src/ui/{attachment_chips.ts → transcript/attachment_chips.ts} +2 -2
  129. package/src/ui/{message_actions.ts → transcript/message_actions.ts} +2 -2
  130. package/src/ui/{suggestion_chips.ts → transcript/suggestion_chips.ts} +1 -1
  131. package/src/ui/ui_strings.ts +6 -0
  132. package/src/version.ts +1 -1
  133. package/dist/ui/approval_card.d.ts.map +0 -1
  134. package/dist/ui/attach_copy_buttons.d.ts.map +0 -1
  135. package/dist/ui/attachment_chips.d.ts.map +0 -1
  136. package/dist/ui/attachment_tray.d.ts.map +0 -1
  137. package/dist/ui/chart_block.d.ts.map +0 -1
  138. package/dist/ui/chart_spec_from.d.ts.map +0 -1
  139. package/dist/ui/chart_tool.d.ts.map +0 -1
  140. package/dist/ui/checkpoint_menu.d.ts.map +0 -1
  141. package/dist/ui/clamp_launcher.d.ts.map +0 -1
  142. package/dist/ui/clamp_panel.d.ts.map +0 -1
  143. package/dist/ui/confirmation_card.d.ts.map +0 -1
  144. package/dist/ui/copy_payload.d.ts.map +0 -1
  145. package/dist/ui/launcher_drag.d.ts.map +0 -1
  146. package/dist/ui/launcher_placement.d.ts.map +0 -1
  147. package/dist/ui/message_actions.d.ts.map +0 -1
  148. package/dist/ui/page_quote_offer.d.ts.map +0 -1
  149. package/dist/ui/panel_drag.d.ts.map +0 -1
  150. package/dist/ui/place_widget.d.ts.map +0 -1
  151. package/dist/ui/prettify_tool_name.d.ts.map +0 -1
  152. package/dist/ui/question_card.d.ts.map +0 -1
  153. package/dist/ui/quote_selection.d.ts.map +0 -1
  154. package/dist/ui/relative_time.d.ts.map +0 -1
  155. package/dist/ui/render_markdown.d.ts.map +0 -1
  156. package/dist/ui/resize_handle.d.ts.map +0 -1
  157. package/dist/ui/reveal_words.d.ts.map +0 -1
  158. package/dist/ui/run_notice.d.ts.map +0 -1
  159. package/dist/ui/skills_menu.d.ts.map +0 -1
  160. package/dist/ui/stick_to_bottom.d.ts.map +0 -1
  161. package/dist/ui/subagent_panel.d.ts.map +0 -1
  162. package/dist/ui/subagent_update.d.ts.map +0 -1
  163. package/dist/ui/suggestion_chips.d.ts.map +0 -1
  164. package/dist/ui/thoughts_block.d.ts.map +0 -1
  165. package/dist/ui/thread_drawer.d.ts.map +0 -1
  166. package/dist/ui/tool_call_card.d.ts.map +0 -1
  167. package/dist/ui/voice_input.d.ts.map +0 -1
  168. /package/dist/ui/{chart_block.d.ts → charts/chart_block.d.ts} +0 -0
  169. /package/dist/ui/{chart_spec_from.d.ts → charts/chart_spec_from.d.ts} +0 -0
  170. /package/dist/ui/{copy_payload.d.ts → excerpts/copy_payload.d.ts} +0 -0
  171. /package/dist/ui/{page_quote_offer.d.ts → excerpts/page_quote_offer.d.ts} +0 -0
  172. /package/dist/ui/{quote_selection.d.ts → excerpts/quote_selection.d.ts} +0 -0
  173. /package/dist/ui/{clamp_launcher.d.ts → placement/clamp_launcher.d.ts} +0 -0
  174. /package/dist/ui/{clamp_panel.d.ts → placement/clamp_panel.d.ts} +0 -0
  175. /package/dist/ui/{launcher_drag.d.ts → placement/launcher_drag.d.ts} +0 -0
  176. /package/dist/ui/{launcher_placement.d.ts → placement/launcher_placement.d.ts} +0 -0
  177. /package/dist/ui/{panel_drag.d.ts → placement/panel_drag.d.ts} +0 -0
  178. /package/dist/ui/{place_widget.d.ts → placement/place_widget.d.ts} +0 -0
  179. /package/dist/ui/{resize_handle.d.ts → placement/resize_handle.d.ts} +0 -0
  180. /package/dist/ui/{prettify_tool_name.d.ts → progress/prettify_tool_name.d.ts} +0 -0
  181. /package/dist/ui/{run_notice.d.ts → progress/run_notice.d.ts} +0 -0
  182. /package/dist/ui/{subagent_update.d.ts → progress/subagent_update.d.ts} +0 -0
  183. /package/dist/ui/{render_markdown.d.ts → transcript/render_markdown.d.ts} +0 -0
  184. /package/dist/ui/{reveal_words.d.ts → transcript/reveal_words.d.ts} +0 -0
  185. /package/dist/ui/{stick_to_bottom.d.ts → transcript/stick_to_bottom.d.ts} +0 -0
  186. /package/src/ui/{chart_block.ts → charts/chart_block.ts} +0 -0
  187. /package/src/ui/{chart_spec_from.ts → charts/chart_spec_from.ts} +0 -0
  188. /package/src/ui/{copy_payload.ts → excerpts/copy_payload.ts} +0 -0
  189. /package/src/ui/{page_quote_offer.ts → excerpts/page_quote_offer.ts} +0 -0
  190. /package/src/ui/{quote_selection.ts → excerpts/quote_selection.ts} +0 -0
  191. /package/src/ui/{launcher_drag.ts → placement/launcher_drag.ts} +0 -0
  192. /package/src/ui/{panel_drag.ts → placement/panel_drag.ts} +0 -0
  193. /package/src/ui/{place_widget.ts → placement/place_widget.ts} +0 -0
  194. /package/src/ui/{resize_handle.ts → placement/resize_handle.ts} +0 -0
  195. /package/src/ui/{prettify_tool_name.ts → progress/prettify_tool_name.ts} +0 -0
  196. /package/src/ui/{run_notice.ts → progress/run_notice.ts} +0 -0
  197. /package/src/ui/{render_markdown.ts → transcript/render_markdown.ts} +0 -0
  198. /package/src/ui/{reveal_words.ts → transcript/reveal_words.ts} +0 -0
  199. /package/src/ui/{stick_to_bottom.ts → transcript/stick_to_bottom.ts} +0 -0
@@ -61,47 +61,45 @@ import { createPageMapContext, type PageMap } from "../tools/page_map.js";
61
61
  import { createPageStateTools, type PageState } from "../tools/page_state.js";
62
62
  import { parseToolCatalog, type ToolCatalogEntry } from "../tools/parse_tool_catalog.js";
63
63
  import { createRouteTools, type RouteMap } from "../tools/route_map.js";
64
+ import { renderChart } from "../ui/charts/chart_block.js";
65
+ import { chartSpecFrom } from "../ui/charts/chart_spec_from.js";
66
+ import { CHART_TOOL_NAME, createChartTool } from "../ui/charts/chart_tool.js";
67
+ import { AttachmentTray } from "../ui/composer/attachment_tray.js";
68
+ import { SkillsMenu } from "../ui/composer/skills_menu.js";
69
+ import { VoiceInput } from "../ui/composer/voice_input.js";
70
+ import { attachCopyButtons } from "../ui/excerpts/attach_copy_buttons.js";
71
+ import { copyPayload } from "../ui/excerpts/copy_payload.js";
72
+ import { attachQuoteOffer, type PageQuoteOffer } from "../ui/excerpts/page_quote_offer.js";
73
+ import { asQuote, quotableSelection } from "../ui/excerpts/quote_selection.js";
74
+ import { CheckpointMenu, type CheckpointVerb } from "../ui/history/checkpoint_menu.js";
75
+ import type { RelativeTimeFormatter } from "../ui/history/relative_time.js";
76
+ import { ThreadDrawer } from "../ui/history/thread_drawer.js";
64
77
  import {
65
78
  type ApprovalRenderer,
66
79
  type ApprovalRequest,
67
80
  requestApproval,
68
- } from "../ui/approval_card.js";
69
- import { attachCopyButtons } from "../ui/attach_copy_buttons.js";
70
- import { renderAttachmentChips } from "../ui/attachment_chips.js";
71
- import { AttachmentTray } from "../ui/attachment_tray.js";
72
- import { renderChart } from "../ui/chart_block.js";
73
- import { chartSpecFrom } from "../ui/chart_spec_from.js";
74
- import { CHART_TOOL_NAME, createChartTool } from "../ui/chart_tool.js";
75
- import { CheckpointMenu, type CheckpointVerb } from "../ui/checkpoint_menu.js";
76
- import { clampLauncher } from "../ui/clamp_launcher.js";
77
- import { clampPanel } from "../ui/clamp_panel.js";
78
- import { type ConfirmationRequest, requestConfirmation } from "../ui/confirmation_card.js";
79
- import { copyPayload } from "../ui/copy_payload.js";
80
- import { enableLauncherDrag } from "../ui/launcher_drag.js";
81
+ } from "../ui/interrupts/approval_card.js";
82
+ import {
83
+ type ConfirmationRequest,
84
+ requestConfirmation,
85
+ } from "../ui/interrupts/confirmation_card.js";
86
+ import {
87
+ type QuestionRenderer,
88
+ type QuestionRequest,
89
+ requestQuestion,
90
+ } from "../ui/interrupts/question_card.js";
91
+ import { clampLauncher } from "../ui/placement/clamp_launcher.js";
92
+ import { clampPanel } from "../ui/placement/clamp_panel.js";
93
+ import { enableLauncherDrag } from "../ui/placement/launcher_drag.js";
81
94
  import {
82
95
  type ExpandCorner,
83
96
  type Extent,
84
97
  type LauncherBox,
85
98
  launcherPlacement,
86
99
  type ViewportBox,
87
- } from "../ui/launcher_placement.js";
88
- import {
89
- attachMessageActions,
90
- messageActionBar,
91
- messageActionButton,
92
- } from "../ui/message_actions.js";
93
- import { attachQuoteOffer, type PageQuoteOffer } from "../ui/page_quote_offer.js";
94
- import { enablePanelDrag } from "../ui/panel_drag.js";
95
- import { placeWidget } from "../ui/place_widget.js";
96
- import { prettifyToolName } from "../ui/prettify_tool_name.js";
97
- import {
98
- type QuestionRenderer,
99
- type QuestionRequest,
100
- requestQuestion,
101
- } from "../ui/question_card.js";
102
- import { asQuote, quotableSelection } from "../ui/quote_selection.js";
103
- import type { RelativeTimeFormatter } from "../ui/relative_time.js";
104
- import { renderMarkdown } from "../ui/render_markdown.js";
100
+ } from "../ui/placement/launcher_placement.js";
101
+ import { enablePanelDrag } from "../ui/placement/panel_drag.js";
102
+ import { placeWidget } from "../ui/placement/place_widget.js";
105
103
  import {
106
104
  createResizeHandle,
107
105
  gripName,
@@ -110,24 +108,35 @@ import {
110
108
  type ResizeAxis,
111
109
  type ResizeGrip,
112
110
  type ResizeSize,
113
- } from "../ui/resize_handle.js";
114
- import { wrapWords } from "../ui/reveal_words.js";
115
- import { renderRunNotice } from "../ui/run_notice.js";
116
- import { SkillsMenu } from "../ui/skills_menu.js";
117
- import { createStickToBottom, type StickToBottom } from "../ui/stick_to_bottom.js";
118
- import { STYLES } from "../ui/styles.js";
119
- import { SubAgentPanel, type SubAgentPhase, type SubAgentUpdate } from "../ui/subagent_panel.js";
120
- import { subAgentUpdate } from "../ui/subagent_update.js";
121
- import { renderSuggestionChips } from "../ui/suggestion_chips.js";
122
- import { ThoughtsBlock } from "../ui/thoughts_block.js";
123
- import { ThreadDrawer } from "../ui/thread_drawer.js";
111
+ } from "../ui/placement/resize_handle.js";
112
+ import { prettifyToolName } from "../ui/progress/prettify_tool_name.js";
113
+ import { renderRunNotice } from "../ui/progress/run_notice.js";
114
+ import {
115
+ SubAgentPanel,
116
+ type SubAgentPhase,
117
+ type SubAgentUpdate,
118
+ } from "../ui/progress/subagent_panel.js";
119
+ import { subAgentUpdate } from "../ui/progress/subagent_update.js";
120
+ import { ThoughtsBlock } from "../ui/progress/thoughts_block.js";
124
121
  import {
125
122
  ToolCallCard,
126
123
  type ToolDisplayMode,
127
124
  type ToolPayloadFormatter,
128
- } from "../ui/tool_call_card.js";
125
+ } from "../ui/progress/tool_call_card.js";
126
+ import { STYLES } from "../ui/styles.js";
127
+ import { renderAttachmentChips } from "../ui/transcript/attachment_chips.js";
128
+ import {
129
+ attachMessageActions,
130
+ messageActionBar,
131
+ messageActionButton,
132
+ } from "../ui/transcript/message_actions.js";
133
+ import { renderMarkdown } from "../ui/transcript/render_markdown.js";
134
+ import { wrapWords } from "../ui/transcript/reveal_words.js";
135
+ import { createStickToBottom, type StickToBottom } from "../ui/transcript/stick_to_bottom.js";
136
+ import { renderSuggestionChips } from "../ui/transcript/suggestion_chips.js";
129
137
  import { DEFAULT_UI_STRINGS, mergeUiStrings, type UiStrings } from "../ui/ui_strings.js";
130
- import { VoiceInput } from "../ui/voice_input.js";
138
+ import type { ActivityRegistration } from "./activity_registration.js";
139
+ import type { ActivityRenderer } from "./activity_renderer.js";
131
140
  import {
132
141
  AgUiClient,
133
142
  type AgUiClientHandlers,
@@ -143,6 +152,17 @@ import {
143
152
  writeStoredItem,
144
153
  } from "./conversation_store.js";
145
154
  import { type AgentFactory, createHttpAgent } from "./create_http_agent.js";
155
+ import type { AttachmentsDetail } from "./events/attachments_detail.js";
156
+ import type { CustomAgentDetail } from "./events/custom_agent_detail.js";
157
+ import type { FeedbackDetail } from "./events/feedback_detail.js";
158
+ import type { InvalidateDetail } from "./events/invalidate_detail.js";
159
+ import type { RunFinishedDetail } from "./events/run_finished_detail.js";
160
+ import type { StateDetail } from "./events/state_detail.js";
161
+ import type { SubmitDetail } from "./events/submit_detail.js";
162
+ import type { ToggleDetail } from "./events/toggle_detail.js";
163
+ import type { ToolRun } from "./events/tool_run.js";
164
+ import type { UnreadDetail } from "./events/unread_detail.js";
165
+ import type { MessageRole } from "./message_role.js";
146
166
  import { RemoteConversationStore } from "./remote_conversation_store.js";
147
167
  import { RunIndex } from "./run_index.js";
148
168
  import { toolStatusFromOutcome } from "./tool_outcome.js";
@@ -150,140 +170,6 @@ import { type TranscribeHandler, transcribeAudio } from "./transcribe_audio.js";
150
170
  import { type UploadHandler, uploadAttachment } from "./upload_attachment.js";
151
171
  import { mintThread, warnOnCrossOriginCredentials, withCredentials } from "./utils.js";
152
172
 
153
- /** The role a rendered chat message takes. */
154
- export type MessageRole = (typeof MESSAGE_ROLE)[keyof typeof MESSAGE_ROLE];
155
-
156
- /** `detail` shape of the {@link SUBMIT_EVENT} CustomEvent. */
157
- export interface SubmitDetail {
158
- readonly content: string;
159
- /** Durable refs for the files attached to this message (empty when none). */
160
- readonly attachments: readonly AttachmentRef[];
161
- }
162
-
163
- /** `detail` shape of the {@link ATTACHMENT_EVENT} CustomEvent. */
164
- export interface AttachmentsDetail {
165
- /** Durable refs for every file that has finished uploading. */
166
- readonly attachments: readonly AttachmentRef[];
167
- /** How many files are still uploading; a send now would leave these behind. */
168
- readonly pending: number;
169
- }
170
-
171
- /** `detail` shape of the {@link STATE_EVENT} CustomEvent. */
172
- /** {@link FEEDBACK_EVENT} detail: what was rated, and how. */
173
- export interface FeedbackDetail {
174
- /** The rated message's text, as rendered. */
175
- readonly content: string;
176
- readonly rating: "up" | "down";
177
- }
178
-
179
- export interface StateDetail {
180
- readonly state: Readonly<Record<string, unknown>>;
181
- }
182
-
183
- /** One tool that ran during an interaction, as {@link RunFinishedDetail} lists it. */
184
- export interface ToolRun {
185
- readonly name: string;
186
- /**
187
- * Where it executed. `"server"` is the one a data-rendering host cares about:
188
- * a `"client"` tool ran in the host's own handler, so the host already knows
189
- * whatever it did.
190
- */
191
- readonly side: "server" | "client";
192
- }
193
-
194
- /** `detail` shape of the {@link RUN_FINISHED_EVENT} CustomEvent. */
195
- export interface RunFinishedDetail {
196
- /** In settle order. Empty when the interaction called no tools. */
197
- readonly tools: readonly ToolRun[];
198
- /**
199
- * Every key announced during the interaction, de-duplicated, first-seen order.
200
- *
201
- * **This is the field that makes adoption one line** for a host already
202
- * listening here, and the `else` is the whole compatibility story:
203
- *
204
- * ```js
205
- * if (detail.invalidated.length > 0) refetchOnly(detail.invalidated);
206
- * else if (detail.tools.some((t) => t.side === "server")) refetchEverything();
207
- * ```
208
- *
209
- * Empty against a server that announces nothing, so an old server and a new
210
- * client fall through to the coarse refetch that shipped before either.
211
- */
212
- readonly invalidated: readonly string[];
213
- }
214
-
215
- /**
216
- * Draw one activity, from its content alone.
217
- *
218
- * The contract is {@link ClientTool.render}'s, and for the same reason rather
219
- * than by analogy. An activity is materialised into a `role: "activity"`
220
- * message, persisted with the transcript, and re-fired on every restore -- so a
221
- * renderer that writes to the page instead of returning DOM fires again on
222
- * every thread load, which is exactly the bug the tool registry's purity rule
223
- * was written to make unmakeable.
224
- *
225
- * - a pure function of `content` -- no host state, no network, no clock;
226
- * - deterministic, so a reload reproduces what was there before;
227
- * - free of effects outside the node it returns, which the component places.
228
- *
229
- * Return `null` for content that says nothing worth drawing. Anything already
230
- * drawn under that message id is then removed: live and reload should agree,
231
- * and the stored content is the version that could not be drawn.
232
- */
233
- export type ActivityRenderer = (content: unknown) => Node | null;
234
-
235
- /** One `activity_type` a host can draw. See {@link AgUiChat.registerActivityRenderer}. */
236
- export interface ActivityRegistration {
237
- /**
238
- * The AG-UI `activity_type` this draws, matched exactly.
239
- *
240
- * An open string the protocol does not enumerate -- which is the whole reason
241
- * this is a registry rather than a branch.
242
- */
243
- readonly type: string;
244
- readonly render: ActivityRenderer;
245
- /**
246
- * Shown in the transcript when something already drawn under this type stops
247
- * being renderable. Omit for an activity whose disappearance needs no
248
- * explanation.
249
- */
250
- readonly removedNotice?: string;
251
- }
252
-
253
- /** `detail` shape of the {@link CUSTOM_AGENT_EVENT} CustomEvent. */
254
- export interface CustomAgentDetail {
255
- /** The `CUSTOM` event's `name`, verbatim. An open string; never interpreted here. */
256
- readonly name: string;
257
- /** Its `value`, verbatim and unparsed. `unknown` because the protocol says nothing about it. */
258
- readonly value: unknown;
259
- }
260
-
261
- /** `detail` shape of the {@link INVALIDATE_EVENT} CustomEvent. */
262
- export interface InvalidateDetail {
263
- /**
264
- * The resources that moved, as the server named them.
265
- *
266
- * **Opaque strings, and matching is exact.** `orders/42` does not imply
267
- * `orders` -- a prefix rule would be this component guessing at a scheme it
268
- * does not own, and `orders/1` would match `orders/11`. A server that wants
269
- * the collection refreshed names it. Your own matching may be hierarchical,
270
- * because in your vocabulary the scheme is known.
271
- */
272
- readonly keys: readonly string[];
273
- /** What caused the write -- usually the tool's name. `null` when unstated. */
274
- readonly reason: string | null;
275
- }
276
-
277
- /** `detail` shape of the {@link TOGGLE_EVENT} CustomEvent. */
278
- export interface ToggleDetail {
279
- readonly collapsed: boolean;
280
- }
281
-
282
- /** `detail` shape of the {@link UNREAD_EVENT} CustomEvent. */
283
- export interface UnreadDetail {
284
- readonly unread: number;
285
- }
286
-
287
173
  /**
288
174
  * Attributes read once while connecting, to decide what chrome exists at all.
289
175
  *
@@ -829,7 +715,17 @@ export class AgUiChat extends HTMLElement {
829
715
  readonly #checkpoints: CheckpointMenu;
830
716
  /** Built lazily from `data-runs-url`; `null` when the host didn't opt in. */
831
717
  #runIndex: RunIndex | null = null;
832
- readonly #skillHint: HTMLDivElement;
718
+ /**
719
+ * The one-line hint above the composer, cleared by the next keystroke.
720
+ *
721
+ * Two things write it -- a skill whose template is short of a field, and a
722
+ * run continuation picked with nothing typed -- and both say the same kind of
723
+ * thing: what the composer still needs before this can go. Its `part` stays
724
+ * `skill-hint`, which the skills feature named and the README documents;
725
+ * renaming a part is breaking, and a second hint element in the same slot
726
+ * would be worse than one whose name is a release older than its job.
727
+ */
728
+ readonly #composerHint: HTMLDivElement;
833
729
  /** File-picker button + hidden input + tray slot; the tray mounts on connect. */
834
730
  readonly #attachButton: HTMLButtonElement;
835
731
  readonly #fileInput: HTMLInputElement;
@@ -1052,7 +948,7 @@ export class AgUiChat extends HTMLElement {
1052
948
  this.#input = document.createElement("textarea");
1053
949
  this.#send = document.createElement("button");
1054
950
  this.#title = document.createElement("span");
1055
- this.#skillHint = document.createElement("div");
951
+ this.#composerHint = document.createElement("div");
1056
952
  this.#attachButton = document.createElement("button");
1057
953
  this.#fileInput = document.createElement("input");
1058
954
  this.#attachSlot = document.createElement("div");
@@ -1144,10 +1040,29 @@ export class AgUiChat extends HTMLElement {
1144
1040
  async #continueRun(runId: string, verb: CheckpointVerb): Promise<void> {
1145
1041
  const index = this.#runs();
1146
1042
  if (index === null) {
1043
+ // Unreachable from the built-in control: the header button is only
1044
+ // rendered when `#runs()` is configured, so a row to pick cannot exist
1045
+ // without one. A host calling `openCheckpoints()` regardless gets the
1046
+ // documented empty panel, which has no rows either. Typed, not silent.
1147
1047
  return;
1148
1048
  }
1149
1049
  const content = this.#input.value.trim();
1150
1050
  if (content === "") {
1051
+ // A continuation sends *only* the next turn -- the snapshot supplies
1052
+ // everything before it -- so with an empty composer there is nothing to
1053
+ // send. Returning here was the same failure the endpoint guard above had:
1054
+ // the row's button closes the panel before this runs, so the widget
1055
+ // visibly reacted and then did nothing, which reads as a resume that was
1056
+ // attempted and lost rather than one that never started.
1057
+ //
1058
+ // Said at the composer rather than in the transcript, because that is
1059
+ // where the fix goes and because the hint clears itself on the first
1060
+ // keystroke -- a transcript notice for a recoverable slip would outlive
1061
+ // the slip. Focus follows for the same reason `#applySkill` moves it when
1062
+ // a template is short of a field.
1063
+ this.#composerHint.textContent = this.#strings.continueNeedsTurn;
1064
+ this.#composerHint.hidden = false;
1065
+ this.#input.focus();
1151
1066
  return;
1152
1067
  }
1153
1068
  this.#input.value = "";
@@ -1805,21 +1720,45 @@ export class AgUiChat extends HTMLElement {
1805
1720
  return value !== null && value !== "false";
1806
1721
  }
1807
1722
 
1808
- /** Parse the inline `data-strings` JSON overrides (empty when absent/malformed). */
1809
- #readStringOverrides(): Partial<UiStrings> {
1810
- const raw = this.getAttribute("data-strings");
1723
+ /**
1724
+ * Parse a JSON-valued attribute, saying so when it will not parse.
1725
+ *
1726
+ * `null` for an absent attribute, and `null` again for one that is not JSON --
1727
+ * but not quietly the second time. Quoting JSON inside an HTML attribute is
1728
+ * fiddly, and the result of getting it wrong is indistinguishable from the
1729
+ * feature being switched off: no chips appear, or the strings stay English,
1730
+ * with nothing anywhere saying why. That is the same failure `data-paste-attach`
1731
+ * already reports for a value it cannot read.
1732
+ *
1733
+ * Console only. A page author's typo is not the reader's business, nothing the
1734
+ * reader did was refused, and the degraded widget is still perfectly usable.
1735
+ */
1736
+ #readJsonAttribute(name: string): unknown {
1737
+ const raw = this.getAttribute(name);
1811
1738
  if (raw === null) {
1812
- return {};
1739
+ return null;
1813
1740
  }
1814
1741
  try {
1815
- const parsed: unknown = JSON.parse(raw);
1816
- if (typeof parsed === "object" && parsed !== null) {
1817
- return parsed as Partial<UiStrings>;
1818
- }
1742
+ return JSON.parse(raw);
1819
1743
  } catch {
1820
- // Malformed JSON — fall back to the defaults rather than failing to mount.
1744
+ console.warn(
1745
+ `<ag-ui-chat>: ${name} is not valid JSON, so it was ignored entirely and ` +
1746
+ "the built-in default is being used. Check the quoting -- JSON inside " +
1747
+ "an HTML attribute needs single quotes around the attribute value, or " +
1748
+ "its own double quotes escaped.",
1749
+ );
1750
+ return null;
1821
1751
  }
1822
- return {};
1752
+ }
1753
+
1754
+ /** Parse the inline `data-strings` JSON overrides (empty when absent/malformed). */
1755
+ #readStringOverrides(): Partial<UiStrings> {
1756
+ const parsed = this.#readJsonAttribute("data-strings");
1757
+ // A JSON number or string parses fine and overrides nothing. Not warned
1758
+ // about separately: it is the same "this attribute did not take effect"
1759
+ // as a parse failure, and the warning above already covers the spelling
1760
+ // that produces it by accident.
1761
+ return typeof parsed === "object" && parsed !== null ? (parsed as Partial<UiStrings>) : {};
1823
1762
  }
1824
1763
 
1825
1764
  /**
@@ -2278,15 +2217,9 @@ export class AgUiChat extends HTMLElement {
2278
2217
 
2279
2218
  /** Parse the inline `data-skills` JSON catalog (empty when absent/malformed). */
2280
2219
  #readEmbeddedSkills(): readonly Skill[] {
2281
- const raw = this.getAttribute("data-skills");
2282
- if (raw === null) {
2283
- return [];
2284
- }
2285
- try {
2286
- return parseSkills(JSON.parse(raw));
2287
- } catch {
2288
- return [];
2289
- }
2220
+ // `parseSkills` drops anything that is not a well-formed skill, `null`
2221
+ // included, so the absent and unparseable cases need no branch here.
2222
+ return parseSkills(this.#readJsonAttribute("data-skills"));
2290
2223
  }
2291
2224
 
2292
2225
  /** Fetch the backend skills catalog from `data-skills-url`, if set. */
@@ -2329,7 +2262,7 @@ export class AgUiChat extends HTMLElement {
2329
2262
  */
2330
2263
  #applySkill(skill: Skill): void {
2331
2264
  if (skill.prompt === undefined) {
2332
- this.#skillHint.hidden = true;
2265
+ this.#composerHint.hidden = true;
2333
2266
  void this.sendMessage(`/${skill.name}`);
2334
2267
  return;
2335
2268
  }
@@ -2341,17 +2274,17 @@ export class AgUiChat extends HTMLElement {
2341
2274
  // keystroke replaces it. Blocking with a hint alone left whatever the
2342
2275
  // user had typed to open the palette — a lone "/" — sitting there, which
2343
2276
  // says nothing about what the skill wanted or how to give it.
2344
- this.#skillHint.textContent = this.#strings.skillNeeds
2277
+ this.#composerHint.textContent = this.#strings.skillNeeds
2345
2278
  .replace("{title}", skill.title)
2346
2279
  .replace("{fields}", missing.join(", "));
2347
- this.#skillHint.hidden = false;
2280
+ this.#composerHint.hidden = false;
2348
2281
  this.#input.value = text;
2349
2282
  this.#autoGrow();
2350
2283
  this.#input.focus();
2351
2284
  this.#selectFirstPlaceholder(text);
2352
2285
  return;
2353
2286
  }
2354
- this.#skillHint.hidden = true;
2287
+ this.#composerHint.hidden = true;
2355
2288
  this.#input.value = text;
2356
2289
  this.#autoGrow();
2357
2290
  if (skill.sendImmediately === false) {
@@ -4318,9 +4251,9 @@ export class AgUiChat extends HTMLElement {
4318
4251
  void this.#submit();
4319
4252
  });
4320
4253
 
4321
- this.#skillHint.className = "skill-hint";
4322
- this.#skillHint.setAttribute("part", "skill-hint");
4323
- this.#skillHint.hidden = true;
4254
+ this.#composerHint.className = "skill-hint";
4255
+ this.#composerHint.setAttribute("part", "skill-hint");
4256
+ this.#composerHint.hidden = true;
4324
4257
 
4325
4258
  // File-upload affordance: a paperclip button (hidden until
4326
4259
  // `data-attachments-url` is wired) opening a hidden multi-file input.
@@ -4352,8 +4285,9 @@ export class AgUiChat extends HTMLElement {
4352
4285
  tools.append(this.#attachButton, this.#voiceSlot, this.#send);
4353
4286
  composer.append(this.#input, tools);
4354
4287
  inputRow.append(composer, this.#fileInput);
4355
- // Skill surfaces sit just above the input: palette (opens on `/`), chips,
4356
- // the missing-placeholder hint, and the pending-attachments tray.
4288
+ // Composer surfaces sit just above the input: the skills palette (opens on
4289
+ // `/`), the chips, the hint saying what the composer still needs, and the
4290
+ // pending-attachments tray.
4357
4291
  this.#messagesWrap.className = "messages-wrap";
4358
4292
  // Sibling of the list inside a shared box, not a child of it: the
4359
4293
  // affordance offering to scroll must not scroll away with the content.
@@ -4364,7 +4298,7 @@ export class AgUiChat extends HTMLElement {
4364
4298
  this.#messagesWrap,
4365
4299
  this.#skillsMenu.palette,
4366
4300
  this.#skillsMenu.chips,
4367
- this.#skillHint,
4301
+ this.#composerHint,
4368
4302
  this.#queuedRow,
4369
4303
  this.#attachSlot,
4370
4304
  inputRow,
@@ -4689,10 +4623,16 @@ export class AgUiChat extends HTMLElement {
4689
4623
  this.#emptyWrap.hidden = this.#messages.childElementCount > 1;
4690
4624
  }
4691
4625
 
4692
- /** Forward input changes to the skills palette and clear any stale hint. */
4626
+ /**
4627
+ * Forward input changes to the skills palette and clear any stale hint.
4628
+ *
4629
+ * Typing is the answer to every hint that surface carries -- a skill short of
4630
+ * a field, a continuation short of its next turn -- so the keystroke that
4631
+ * starts answering it is the right moment to take it down.
4632
+ */
4693
4633
  #onInput(): void {
4694
4634
  this.#skillsMenu.onInput(this.#input.value);
4695
- this.#skillHint.hidden = true;
4635
+ this.#composerHint.hidden = true;
4696
4636
  this.#autoGrow();
4697
4637
  // Typing puts the composer back in the user's hands: the next ArrowUp
4698
4638
  // starts from the newest turn again rather than continuing a walk through
@@ -4992,8 +4932,39 @@ export class AgUiChat extends HTMLElement {
4992
4932
  );
4993
4933
  }
4994
4934
 
4935
+ /**
4936
+ * Hand the message to the client, or say why it is going nowhere.
4937
+ *
4938
+ * With no `endpoint` there is nothing to send to, and this used to return
4939
+ * here in silence. That is the worst shape the failure can take, because the
4940
+ * two halves of a send that *did* work have already happened by now: the
4941
+ * user's bubble is on screen and {@link SUBMIT_EVENT} has been dispatched. So
4942
+ * the message looks sent, the composer is empty, the Send button never turns
4943
+ * into Stop, and no request is ever made -- an unanswered question rather
4944
+ * than a broken widget. Nothing reached the console either, so the developer
4945
+ * had no thread to pull and the user had no reason to think anything was
4946
+ * wrong with the page.
4947
+ *
4948
+ * Both audiences are told, because they need different things. The console
4949
+ * carries the developer's version -- the attribute is missing, here is what
4950
+ * to set -- since a missing attribute is a page's mistake and not the
4951
+ * reader's. The transcript carries the reader's, because they are looking at
4952
+ * their own message waiting for a reply that cannot come, and the honest
4953
+ * alternative to one muted line is an indefinite wait.
4954
+ *
4955
+ * Said on every attempt rather than once. Each send is a separate thing the
4956
+ * user asked for and did not get, and a once-only report is silence for every
4957
+ * attempt after the first -- which is the defect again, just later.
4958
+ */
4995
4959
  async #client_send(content: string, attachments: readonly AttachmentRef[]): Promise<void> {
4996
4960
  if (this.endpoint === "") {
4961
+ console.error(
4962
+ "<ag-ui-chat>: no endpoint is set, so this message was not sent and no " +
4963
+ "request was made. Point the element at your AG-UI mount with the " +
4964
+ 'endpoint attribute (endpoint="/agent/"), or assign chat.endpoint ' +
4965
+ "before sending.",
4966
+ );
4967
+ this.#appendNotice("⚠", this.#strings.notConnected, "not-connected");
4997
4968
  return;
4998
4969
  }
4999
4970
  await this.#ensureClient().send(content, attachments);
@@ -5423,6 +5394,26 @@ export class AgUiChat extends HTMLElement {
5423
5394
  this.#streamDeltas += 1;
5424
5395
  },
5425
5396
  onTextEnd: (buffer) => {
5397
+ // A text message that carried no content is a declaration, not an
5398
+ // answer, and drawing one puts an empty bubble above every tool call.
5399
+ //
5400
+ // `TOOL_CALL_START` names the assistant message a call belongs to, and
5401
+ // a response whose first part is a tool call has no text to open that
5402
+ // message with. pydantic-ai 2.37 started opening and closing an empty
5403
+ // one there so the id names a message the stream actually announced --
5404
+ // before that it named one no event carried, which a client could only
5405
+ // answer by inventing an id of its own that matches nothing echoed
5406
+ // back. So this envelope is a correctness fix upstream, it is legal
5407
+ // AG-UI, and any server may send one.
5408
+ //
5409
+ // `#renderHistoricMessage` already declines to draw a bubble for an
5410
+ // assistant message with no text. Without the same rule here the live
5411
+ // transcript and the reloaded one disagree about the same
5412
+ // conversation, which is the harder half of the bug to notice.
5413
+ if (buffer === "") {
5414
+ this.#endStream();
5415
+ return;
5416
+ }
5426
5417
  const bubble = this.#streamInto(buffer);
5427
5418
  // Only reveal word-by-word when the message arrived at once. If it
5428
5419
  // streamed across multiple deltas it already revealed progressively, so
@@ -0,0 +1,9 @@
1
+ import type { AttachmentRef } from "../attachment.js";
2
+
3
+ /** `detail` shape of the {@link ATTACHMENT_EVENT} CustomEvent. */
4
+ export interface AttachmentsDetail {
5
+ /** Durable refs for every file that has finished uploading. */
6
+ readonly attachments: readonly AttachmentRef[];
7
+ /** How many files are still uploading; a send now would leave these behind. */
8
+ readonly pending: number;
9
+ }
@@ -0,0 +1,7 @@
1
+ /** `detail` shape of the {@link CUSTOM_AGENT_EVENT} CustomEvent. */
2
+ export interface CustomAgentDetail {
3
+ /** The `CUSTOM` event's `name`, verbatim. An open string; never interpreted here. */
4
+ readonly name: string;
5
+ /** Its `value`, verbatim and unparsed. `unknown` because the protocol says nothing about it. */
6
+ readonly value: unknown;
7
+ }
@@ -0,0 +1,6 @@
1
+ /** {@link FEEDBACK_EVENT} detail: what was rated, and how. */
2
+ export interface FeedbackDetail {
3
+ /** The rated message's text, as rendered. */
4
+ readonly content: string;
5
+ readonly rating: "up" | "down";
6
+ }
@@ -0,0 +1,15 @@
1
+ /** `detail` shape of the {@link INVALIDATE_EVENT} CustomEvent. */
2
+ export interface InvalidateDetail {
3
+ /**
4
+ * The resources that moved, as the server named them.
5
+ *
6
+ * **Opaque strings, and matching is exact.** `orders/42` does not imply
7
+ * `orders` -- a prefix rule would be this component guessing at a scheme it
8
+ * does not own, and `orders/1` would match `orders/11`. A server that wants
9
+ * the collection refreshed names it. Your own matching may be hierarchical,
10
+ * because in your vocabulary the scheme is known.
11
+ */
12
+ readonly keys: readonly string[];
13
+ /** What caused the write -- usually the tool's name. `null` when unstated. */
14
+ readonly reason: string | null;
15
+ }
@@ -0,0 +1,22 @@
1
+ import type { ToolRun } from "./tool_run.js";
2
+
3
+ /** `detail` shape of the {@link RUN_FINISHED_EVENT} CustomEvent. */
4
+ export interface RunFinishedDetail {
5
+ /** In settle order. Empty when the interaction called no tools. */
6
+ readonly tools: readonly ToolRun[];
7
+ /**
8
+ * Every key announced during the interaction, de-duplicated, first-seen order.
9
+ *
10
+ * **This is the field that makes adoption one line** for a host already
11
+ * listening here, and the `else` is the whole compatibility story:
12
+ *
13
+ * ```js
14
+ * if (detail.invalidated.length > 0) refetchOnly(detail.invalidated);
15
+ * else if (detail.tools.some((t) => t.side === "server")) refetchEverything();
16
+ * ```
17
+ *
18
+ * Empty against a server that announces nothing, so an old server and a new
19
+ * client fall through to the coarse refetch that shipped before either.
20
+ */
21
+ readonly invalidated: readonly string[];
22
+ }
@@ -0,0 +1,4 @@
1
+ /** `detail` shape of the {@link STATE_EVENT} CustomEvent. */
2
+ export interface StateDetail {
3
+ readonly state: Readonly<Record<string, unknown>>;
4
+ }
@@ -0,0 +1,8 @@
1
+ import type { AttachmentRef } from "../attachment.js";
2
+
3
+ /** `detail` shape of the {@link SUBMIT_EVENT} CustomEvent. */
4
+ export interface SubmitDetail {
5
+ readonly content: string;
6
+ /** Durable refs for the files attached to this message (empty when none). */
7
+ readonly attachments: readonly AttachmentRef[];
8
+ }
@@ -0,0 +1,4 @@
1
+ /** `detail` shape of the {@link TOGGLE_EVENT} CustomEvent. */
2
+ export interface ToggleDetail {
3
+ readonly collapsed: boolean;
4
+ }
@@ -0,0 +1,10 @@
1
+ /** One tool that ran during an interaction, as {@link RunFinishedDetail} lists it. */
2
+ export interface ToolRun {
3
+ readonly name: string;
4
+ /**
5
+ * Where it executed. `"server"` is the one a data-rendering host cares about:
6
+ * a `"client"` tool ran in the host's own handler, so the host already knows
7
+ * whatever it did.
8
+ */
9
+ readonly side: "server" | "client";
10
+ }