@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.
- package/CHANGELOG.md +140 -1
- package/README.md +9 -5
- package/dist/ag-ui-web-component.bundle.js +81 -81
- package/dist/ag-ui-web-component.bundle.js.map +4 -4
- package/dist/core/activity_registration.d.ts +19 -0
- package/dist/core/activity_registration.d.ts.map +1 -0
- package/dist/core/activity_renderer.d.ts +20 -0
- package/dist/core/activity_renderer.d.ts.map +1 -0
- package/dist/core/ag_ui_chat.d.ts +6 -126
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/core/events/attachments_detail.d.ts +9 -0
- package/dist/core/events/attachments_detail.d.ts.map +1 -0
- package/dist/core/events/custom_agent_detail.d.ts +8 -0
- package/dist/core/events/custom_agent_detail.d.ts.map +1 -0
- package/dist/core/events/feedback_detail.d.ts +7 -0
- package/dist/core/events/feedback_detail.d.ts.map +1 -0
- package/dist/core/events/invalidate_detail.d.ts +16 -0
- package/dist/core/events/invalidate_detail.d.ts.map +1 -0
- package/dist/core/events/run_finished_detail.d.ts +22 -0
- package/dist/core/events/run_finished_detail.d.ts.map +1 -0
- package/dist/core/events/state_detail.d.ts +5 -0
- package/dist/core/events/state_detail.d.ts.map +1 -0
- package/dist/core/events/submit_detail.d.ts +8 -0
- package/dist/core/events/submit_detail.d.ts.map +1 -0
- package/dist/core/events/toggle_detail.d.ts +5 -0
- package/dist/core/events/toggle_detail.d.ts.map +1 -0
- package/dist/core/events/tool_run.d.ts +11 -0
- package/dist/core/events/tool_run.d.ts.map +1 -0
- package/dist/core/events/unread_detail.d.ts +5 -0
- package/dist/core/events/unread_detail.d.ts.map +1 -0
- package/dist/core/message_role.d.ts +4 -0
- package/dist/core/message_role.d.ts.map +1 -0
- package/dist/core/tool_outcome.d.ts +1 -1
- package/dist/core/tool_outcome.d.ts.map +1 -1
- package/dist/index.d.ts +30 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6242 -6178
- package/dist/index.js.map +4 -4
- package/dist/ui/charts/chart_block.d.ts.map +1 -0
- package/dist/ui/charts/chart_spec_from.d.ts.map +1 -0
- package/dist/ui/{chart_tool.d.ts → charts/chart_tool.d.ts} +1 -1
- package/dist/ui/charts/chart_tool.d.ts.map +1 -0
- package/dist/ui/{attachment_tray.d.ts → composer/attachment_tray.d.ts} +3 -3
- package/dist/ui/composer/attachment_tray.d.ts.map +1 -0
- package/dist/ui/{skills_menu.d.ts → composer/skills_menu.d.ts} +1 -1
- package/dist/ui/composer/skills_menu.d.ts.map +1 -0
- package/dist/ui/{voice_input.d.ts → composer/voice_input.d.ts} +2 -2
- package/dist/ui/composer/voice_input.d.ts.map +1 -0
- package/dist/ui/{attach_copy_buttons.d.ts → excerpts/attach_copy_buttons.d.ts} +1 -1
- package/dist/ui/excerpts/attach_copy_buttons.d.ts.map +1 -0
- package/dist/ui/excerpts/copy_payload.d.ts.map +1 -0
- package/dist/ui/excerpts/page_quote_offer.d.ts.map +1 -0
- package/dist/ui/excerpts/quote_selection.d.ts.map +1 -0
- package/dist/ui/{checkpoint_menu.d.ts → history/checkpoint_menu.d.ts} +2 -2
- package/dist/ui/history/checkpoint_menu.d.ts.map +1 -0
- package/dist/ui/{relative_time.d.ts → history/relative_time.d.ts} +1 -1
- package/dist/ui/history/relative_time.d.ts.map +1 -0
- package/dist/ui/{thread_drawer.d.ts → history/thread_drawer.d.ts} +2 -2
- package/dist/ui/history/thread_drawer.d.ts.map +1 -0
- package/dist/ui/{approval_card.d.ts → interrupts/approval_card.d.ts} +1 -1
- package/dist/ui/interrupts/approval_card.d.ts.map +1 -0
- package/dist/ui/{confirmation_card.d.ts → interrupts/confirmation_card.d.ts} +1 -1
- package/dist/ui/interrupts/confirmation_card.d.ts.map +1 -0
- package/dist/ui/{question_card.d.ts → interrupts/question_card.d.ts} +1 -1
- package/dist/ui/interrupts/question_card.d.ts.map +1 -0
- package/dist/ui/placement/clamp_launcher.d.ts.map +1 -0
- package/dist/ui/placement/clamp_panel.d.ts.map +1 -0
- package/dist/ui/placement/launcher_drag.d.ts.map +1 -0
- package/dist/ui/placement/launcher_placement.d.ts.map +1 -0
- package/dist/ui/placement/panel_drag.d.ts.map +1 -0
- package/dist/ui/placement/place_widget.d.ts.map +1 -0
- package/dist/ui/placement/resize_handle.d.ts.map +1 -0
- package/dist/ui/progress/prettify_tool_name.d.ts.map +1 -0
- package/dist/ui/progress/run_notice.d.ts.map +1 -0
- package/dist/ui/{subagent_panel.d.ts → progress/subagent_panel.d.ts} +2 -2
- package/dist/ui/progress/subagent_panel.d.ts.map +1 -0
- package/dist/ui/progress/subagent_update.d.ts.map +1 -0
- package/dist/ui/{thoughts_block.d.ts → progress/thoughts_block.d.ts} +1 -1
- package/dist/ui/progress/thoughts_block.d.ts.map +1 -0
- package/dist/ui/{tool_call_card.d.ts → progress/tool_call_card.d.ts} +2 -2
- package/dist/ui/progress/tool_call_card.d.ts.map +1 -0
- package/dist/ui/{attachment_chips.d.ts → transcript/attachment_chips.d.ts} +1 -1
- package/dist/ui/transcript/attachment_chips.d.ts.map +1 -0
- package/dist/ui/{message_actions.d.ts → transcript/message_actions.d.ts} +1 -1
- package/dist/ui/transcript/message_actions.d.ts.map +1 -0
- package/dist/ui/transcript/render_markdown.d.ts.map +1 -0
- package/dist/ui/transcript/reveal_words.d.ts.map +1 -0
- package/dist/ui/transcript/stick_to_bottom.d.ts.map +1 -0
- package/dist/ui/{suggestion_chips.d.ts → transcript/suggestion_chips.d.ts} +1 -1
- package/dist/ui/transcript/suggestion_chips.d.ts.map +1 -0
- package/dist/ui/ui_strings.d.ts +4 -0
- package/dist/ui/ui_strings.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/core/activity_registration.ts +19 -0
- package/src/core/activity_renderer.ts +19 -0
- package/src/core/ag_ui_chat.ts +202 -211
- package/src/core/events/attachments_detail.ts +9 -0
- package/src/core/events/custom_agent_detail.ts +7 -0
- package/src/core/events/feedback_detail.ts +6 -0
- package/src/core/events/invalidate_detail.ts +15 -0
- package/src/core/events/run_finished_detail.ts +22 -0
- package/src/core/events/state_detail.ts +4 -0
- package/src/core/events/submit_detail.ts +8 -0
- package/src/core/events/toggle_detail.ts +4 -0
- package/src/core/events/tool_run.ts +10 -0
- package/src/core/events/unread_detail.ts +4 -0
- package/src/core/message_role.ts +4 -0
- package/src/core/tool_outcome.ts +1 -1
- package/src/index.ts +52 -54
- package/src/ui/{chart_tool.ts → charts/chart_tool.ts} +1 -1
- package/src/ui/{attachment_tray.ts → composer/attachment_tray.ts} +5 -5
- package/src/ui/{skills_menu.ts → composer/skills_menu.ts} +1 -1
- package/src/ui/{voice_input.ts → composer/voice_input.ts} +3 -3
- package/src/ui/{attach_copy_buttons.ts → excerpts/attach_copy_buttons.ts} +1 -1
- package/src/ui/{checkpoint_menu.ts → history/checkpoint_menu.ts} +2 -2
- package/src/ui/{relative_time.ts → history/relative_time.ts} +1 -1
- package/src/ui/{thread_drawer.ts → history/thread_drawer.ts} +2 -2
- package/src/ui/{approval_card.ts → interrupts/approval_card.ts} +1 -1
- package/src/ui/{confirmation_card.ts → interrupts/confirmation_card.ts} +1 -1
- package/src/ui/{question_card.ts → interrupts/question_card.ts} +1 -1
- package/src/ui/{clamp_launcher.ts → placement/clamp_launcher.ts} +1 -1
- package/src/ui/{clamp_panel.ts → placement/clamp_panel.ts} +1 -1
- package/src/ui/{launcher_placement.ts → placement/launcher_placement.ts} +1 -1
- package/src/ui/{subagent_panel.ts → progress/subagent_panel.ts} +2 -2
- package/src/ui/{subagent_update.ts → progress/subagent_update.ts} +1 -1
- package/src/ui/{thoughts_block.ts → progress/thoughts_block.ts} +1 -1
- package/src/ui/{tool_call_card.ts → progress/tool_call_card.ts} +2 -2
- package/src/ui/{attachment_chips.ts → transcript/attachment_chips.ts} +2 -2
- package/src/ui/{message_actions.ts → transcript/message_actions.ts} +2 -2
- package/src/ui/{suggestion_chips.ts → transcript/suggestion_chips.ts} +1 -1
- package/src/ui/ui_strings.ts +6 -0
- package/src/version.ts +1 -1
- package/dist/ui/approval_card.d.ts.map +0 -1
- package/dist/ui/attach_copy_buttons.d.ts.map +0 -1
- package/dist/ui/attachment_chips.d.ts.map +0 -1
- package/dist/ui/attachment_tray.d.ts.map +0 -1
- package/dist/ui/chart_block.d.ts.map +0 -1
- package/dist/ui/chart_spec_from.d.ts.map +0 -1
- package/dist/ui/chart_tool.d.ts.map +0 -1
- package/dist/ui/checkpoint_menu.d.ts.map +0 -1
- package/dist/ui/clamp_launcher.d.ts.map +0 -1
- package/dist/ui/clamp_panel.d.ts.map +0 -1
- package/dist/ui/confirmation_card.d.ts.map +0 -1
- package/dist/ui/copy_payload.d.ts.map +0 -1
- package/dist/ui/launcher_drag.d.ts.map +0 -1
- package/dist/ui/launcher_placement.d.ts.map +0 -1
- package/dist/ui/message_actions.d.ts.map +0 -1
- package/dist/ui/page_quote_offer.d.ts.map +0 -1
- package/dist/ui/panel_drag.d.ts.map +0 -1
- package/dist/ui/place_widget.d.ts.map +0 -1
- package/dist/ui/prettify_tool_name.d.ts.map +0 -1
- package/dist/ui/question_card.d.ts.map +0 -1
- package/dist/ui/quote_selection.d.ts.map +0 -1
- package/dist/ui/relative_time.d.ts.map +0 -1
- package/dist/ui/render_markdown.d.ts.map +0 -1
- package/dist/ui/resize_handle.d.ts.map +0 -1
- package/dist/ui/reveal_words.d.ts.map +0 -1
- package/dist/ui/run_notice.d.ts.map +0 -1
- package/dist/ui/skills_menu.d.ts.map +0 -1
- package/dist/ui/stick_to_bottom.d.ts.map +0 -1
- package/dist/ui/subagent_panel.d.ts.map +0 -1
- package/dist/ui/subagent_update.d.ts.map +0 -1
- package/dist/ui/suggestion_chips.d.ts.map +0 -1
- package/dist/ui/thoughts_block.d.ts.map +0 -1
- package/dist/ui/thread_drawer.d.ts.map +0 -1
- package/dist/ui/tool_call_card.d.ts.map +0 -1
- package/dist/ui/voice_input.d.ts.map +0 -1
- /package/dist/ui/{chart_block.d.ts → charts/chart_block.d.ts} +0 -0
- /package/dist/ui/{chart_spec_from.d.ts → charts/chart_spec_from.d.ts} +0 -0
- /package/dist/ui/{copy_payload.d.ts → excerpts/copy_payload.d.ts} +0 -0
- /package/dist/ui/{page_quote_offer.d.ts → excerpts/page_quote_offer.d.ts} +0 -0
- /package/dist/ui/{quote_selection.d.ts → excerpts/quote_selection.d.ts} +0 -0
- /package/dist/ui/{clamp_launcher.d.ts → placement/clamp_launcher.d.ts} +0 -0
- /package/dist/ui/{clamp_panel.d.ts → placement/clamp_panel.d.ts} +0 -0
- /package/dist/ui/{launcher_drag.d.ts → placement/launcher_drag.d.ts} +0 -0
- /package/dist/ui/{launcher_placement.d.ts → placement/launcher_placement.d.ts} +0 -0
- /package/dist/ui/{panel_drag.d.ts → placement/panel_drag.d.ts} +0 -0
- /package/dist/ui/{place_widget.d.ts → placement/place_widget.d.ts} +0 -0
- /package/dist/ui/{resize_handle.d.ts → placement/resize_handle.d.ts} +0 -0
- /package/dist/ui/{prettify_tool_name.d.ts → progress/prettify_tool_name.d.ts} +0 -0
- /package/dist/ui/{run_notice.d.ts → progress/run_notice.d.ts} +0 -0
- /package/dist/ui/{subagent_update.d.ts → progress/subagent_update.d.ts} +0 -0
- /package/dist/ui/{render_markdown.d.ts → transcript/render_markdown.d.ts} +0 -0
- /package/dist/ui/{reveal_words.d.ts → transcript/reveal_words.d.ts} +0 -0
- /package/dist/ui/{stick_to_bottom.d.ts → transcript/stick_to_bottom.d.ts} +0 -0
- /package/src/ui/{chart_block.ts → charts/chart_block.ts} +0 -0
- /package/src/ui/{chart_spec_from.ts → charts/chart_spec_from.ts} +0 -0
- /package/src/ui/{copy_payload.ts → excerpts/copy_payload.ts} +0 -0
- /package/src/ui/{page_quote_offer.ts → excerpts/page_quote_offer.ts} +0 -0
- /package/src/ui/{quote_selection.ts → excerpts/quote_selection.ts} +0 -0
- /package/src/ui/{launcher_drag.ts → placement/launcher_drag.ts} +0 -0
- /package/src/ui/{panel_drag.ts → placement/panel_drag.ts} +0 -0
- /package/src/ui/{place_widget.ts → placement/place_widget.ts} +0 -0
- /package/src/ui/{resize_handle.ts → placement/resize_handle.ts} +0 -0
- /package/src/ui/{prettify_tool_name.ts → progress/prettify_tool_name.ts} +0 -0
- /package/src/ui/{run_notice.ts → progress/run_notice.ts} +0 -0
- /package/src/ui/{render_markdown.ts → transcript/render_markdown.ts} +0 -0
- /package/src/ui/{reveal_words.ts → transcript/reveal_words.ts} +0 -0
- /package/src/ui/{stick_to_bottom.ts → transcript/stick_to_bottom.ts} +0 -0
package/src/core/ag_ui_chat.ts
CHANGED
|
@@ -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 {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
import {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
import {
|
|
79
|
-
import {
|
|
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
|
-
|
|
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 {
|
|
115
|
-
import { renderRunNotice } from "../ui/run_notice.js";
|
|
116
|
-
import {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
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.#
|
|
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
|
-
/**
|
|
1809
|
-
|
|
1810
|
-
|
|
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
|
-
|
|
1816
|
-
if (typeof parsed === "object" && parsed !== null) {
|
|
1817
|
-
return parsed as Partial<UiStrings>;
|
|
1818
|
-
}
|
|
1742
|
+
return JSON.parse(raw);
|
|
1819
1743
|
} catch {
|
|
1820
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
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.#
|
|
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.#
|
|
2277
|
+
this.#composerHint.textContent = this.#strings.skillNeeds
|
|
2345
2278
|
.replace("{title}", skill.title)
|
|
2346
2279
|
.replace("{fields}", missing.join(", "));
|
|
2347
|
-
this.#
|
|
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.#
|
|
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.#
|
|
4322
|
-
this.#
|
|
4323
|
-
this.#
|
|
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
|
-
//
|
|
4356
|
-
// the
|
|
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.#
|
|
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
|
-
/**
|
|
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.#
|
|
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,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,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,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
|
+
}
|