@artooi/ag-ui-web-component 0.39.0 → 0.40.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 +155 -1
- package/README.md +70 -12
- package/dist/ag-ui-web-component.bundle.js +168 -45
- package/dist/ag-ui-web-component.bundle.js.map +3 -3
- package/dist/core/ag_ui_chat.d.ts +7 -3
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/core/agui_client.d.ts +12 -0
- package/dist/core/agui_client.d.ts.map +1 -1
- package/dist/core/client_seed.d.ts +14 -2
- package/dist/core/client_seed.d.ts.map +1 -1
- package/dist/index.js +636 -231
- package/dist/index.js.map +2 -2
- package/dist/tools/tool_catalog.d.ts.map +1 -1
- package/dist/ui/composer/composer_attachments.d.ts +6 -1
- package/dist/ui/composer/composer_attachments.d.ts.map +1 -1
- package/dist/ui/composer/composer_voice.d.ts +3 -0
- package/dist/ui/composer/composer_voice.d.ts.map +1 -1
- package/dist/ui/excerpts/transcript_quote_offer.d.ts +7 -2
- package/dist/ui/excerpts/transcript_quote_offer.d.ts.map +1 -1
- package/dist/ui/history/conversation_history.d.ts +29 -3
- package/dist/ui/history/conversation_history.d.ts.map +1 -1
- package/dist/ui/placement/launcher_drag.d.ts +6 -0
- package/dist/ui/placement/launcher_drag.d.ts.map +1 -1
- package/dist/ui/placement/panel_placement.d.ts +1 -1
- package/dist/ui/placement/panel_placement.d.ts.map +1 -1
- package/dist/ui/styles.d.ts +1 -1
- package/dist/ui/styles.d.ts.map +1 -1
- package/dist/ui/transcript/transcript.d.ts +3 -2
- package/dist/ui/transcript/transcript.d.ts.map +1 -1
- package/dist/ui/ui_strings.d.ts +2 -0
- package/dist/ui/ui_strings.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/ag_ui_chat.ts +217 -64
- package/src/core/agui_client.ts +26 -14
- package/src/core/client_seed.ts +14 -2
- package/src/tools/tool_catalog.ts +63 -12
- package/src/ui/composer/composer_attachments.ts +64 -41
- package/src/ui/composer/composer_voice.ts +5 -0
- package/src/ui/excerpts/transcript_quote_offer.ts +26 -13
- package/src/ui/history/conversation_history.ts +125 -17
- package/src/ui/placement/launcher_drag.ts +104 -89
- package/src/ui/placement/panel_placement.ts +27 -3
- package/src/ui/styles.ts +137 -14
- package/src/ui/transcript/transcript.ts +10 -5
- package/src/ui/ui_strings.ts +3 -0
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,159 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.40.0] — 2026-09-17
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **An `askUserRenderer` that throws now hands the question to the built-in
|
|
15
|
+
question card.** A throw, or a rejected promise, used to escape the `ask_user`
|
|
16
|
+
tool: its card settled as an error quoting the host's message, that message
|
|
17
|
+
went on to the agent as the tool result although it was never written for the
|
|
18
|
+
model, and the pending wait was never closed, so the next Stop aborted the
|
|
19
|
+
signal of a question that had already ended.
|
|
20
|
+
|
|
21
|
+
The renderer decides how the question looks, not whether it is asked -- the
|
|
22
|
+
same rule `approvalRenderer` follows -- so it now falls back to the built-in
|
|
23
|
+
card, with a `console.warn` naming the tool call, and the run carries on as if
|
|
24
|
+
no renderer had been set. The exception is a rejection after the signal has
|
|
25
|
+
fired, which is how a renderer is expected to honour Stop: that wait resolves
|
|
26
|
+
with an empty answer, as the built-in card does on the same signal, with no
|
|
27
|
+
card drawn and no warning.
|
|
28
|
+
|
|
29
|
+
- **On a small viewport the composer stays at the foot of the panel, with the
|
|
30
|
+
greeting over the space above it.** Until a conversation had something in it,
|
|
31
|
+
`page` -- and an `embedded` panel that opts into a greeting -- centred the
|
|
32
|
+
composer between the greeting and the foot at every width. Centring is a shape
|
|
33
|
+
for a screen with room to spare: on a phone the on-screen keyboard takes the
|
|
34
|
+
room, and the composer was left halfway up what remained with an empty band
|
|
35
|
+
under it, which is the part of the screen a thumb is already on. At 600px wide
|
|
36
|
+
and below it now stays at the foot, directly over the keyboard, and the
|
|
37
|
+
greeting takes the space above it. The prompts in `data-starters`, or
|
|
38
|
+
whatever a host slots as `empty`, go to the foot with it and sit against the
|
|
39
|
+
composer: a prompt chip is a way into the conversation, and next to the field
|
|
40
|
+
it starts it reads as one. The greeting takes the middle of what they leave,
|
|
41
|
+
and the middle of the transcript where there are none.
|
|
42
|
+
`data-small-viewport="off"` keeps the centred shape at every width, as it
|
|
43
|
+
keeps the rest of the desktop layout.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- **A tool card called with no arguments stops drawing an empty ARGUMENTS
|
|
48
|
+
heading.** The card hides the region rather than framing an empty object, but
|
|
49
|
+
the region declares its own `display`, which beats the user-agent rule for
|
|
50
|
+
the hidden attribute, so 42px of card was drawn holding a heading over
|
|
51
|
+
nothing -- on every call an agent made with no arguments, in the display mode
|
|
52
|
+
that shows arguments by default, and on a pending card's result region too.
|
|
53
|
+
|
|
54
|
+
- **A checkpoint continuation is let go of when its first save fails.** The
|
|
55
|
+
save runs through `conversationStore` synchronously inside the send, and a
|
|
56
|
+
store is the host's to replace: the built-in one swallows a write the browser
|
|
57
|
+
refused, a server-backed one need not. A throw there left the element holding
|
|
58
|
+
a client that would never run, so every later Resume or Fork was refused for
|
|
59
|
+
it with no way to clear it -- the composer's button is Send until a run
|
|
60
|
+
reports a start, so Stop was never offered -- and `sharedState` went on
|
|
61
|
+
writing into the dead client, which the next run then sent stale. The failure
|
|
62
|
+
is now reported with a `console.warn` and the panel takes another pick.
|
|
63
|
+
|
|
64
|
+
- **A turn typed between picking a checkpoint and its run starting is parked
|
|
65
|
+
rather than raced.** The composer learns a run is going from its first event,
|
|
66
|
+
a request round trip behind the pick, so its button was still Send: a turn
|
|
67
|
+
sent in that window started a second run against the conversation the
|
|
68
|
+
continuation had already frozen to save against, and whichever saved last
|
|
69
|
+
dropped the other's turn from the store while both answers streamed into one
|
|
70
|
+
transcript. The composer now queues it, as it does during a run, and sends it
|
|
71
|
+
when the continuation settles. `sendMessage` no-ops in the same window, as it
|
|
72
|
+
already did during a run.
|
|
73
|
+
|
|
74
|
+
- **An empty row of skill chips stops taking space above the composer.** The
|
|
75
|
+
row is hidden whenever the host offers no skills, which is most elements most
|
|
76
|
+
of the time, but it declares its own `display`, and an author display beats
|
|
77
|
+
the user-agent rule for the hidden attribute. So it kept its 20px of padding
|
|
78
|
+
under every placement: a band of panel between the transcript and the
|
|
79
|
+
composer, reading as the gap under whatever the transcript ended with. The
|
|
80
|
+
palette and the queued row beside it were fixed for this reason already, and
|
|
81
|
+
a tool card's payload regions turned out to be a fourth case, below.
|
|
82
|
+
|
|
83
|
+
- **A checkpoint continuation waits for the run in flight.** Picking Resume or
|
|
84
|
+
Fork while an answer was streaming started a second run beside it, and an
|
|
85
|
+
earlier continuation kept streaming where Stop no longer reached it. The pick
|
|
86
|
+
is now refused with a composer hint, as Retry is; the run in flight is left
|
|
87
|
+
alone and the typed turn stays in the composer. `continueWhileRunning` is new
|
|
88
|
+
in the string table.
|
|
89
|
+
|
|
90
|
+
- **A continued exchange is kept with its conversation.** It was never saved,
|
|
91
|
+
so a reload lost it, and the next message went out without it and with the
|
|
92
|
+
shared state from before the continuation. Each save now writes the
|
|
93
|
+
conversation with the exchange after it, through the existing `saveMessages`
|
|
94
|
+
-- `ClientConversationStore` is unchanged -- and the next message carries
|
|
95
|
+
both. After continuing from an earlier run, what is saved is what the
|
|
96
|
+
transcript shows, not only the turns up to that run. `sharedState` reads a
|
|
97
|
+
running continuation, and `AgUiClient.annotatedMessages` is new: the history
|
|
98
|
+
in the form a save writes it, with how each tool call ended.
|
|
99
|
+
|
|
100
|
+
- **A full-screen panel stays on the visible screen when a keyboard opens under
|
|
101
|
+
the field.** To show the composer, iOS Safari pans the visible area down the
|
|
102
|
+
page, and a panel anchored at the top of the screen stayed where it was: sized
|
|
103
|
+
to the visible height, it showed only its lower part, with the header and the
|
|
104
|
+
greeting off the top and an empty band above the keyboard. That covered
|
|
105
|
+
`page`, `full`, `side` and `sidebar`, and at phone width the corner placements
|
|
106
|
+
too, because they become the whole screen there, and their keyboard lift never
|
|
107
|
+
moved them: a box with its top, height and bottom all set ignores the bottom.
|
|
108
|
+
The element now also publishes how far the visible area is panned, as
|
|
109
|
+
`--ag-ui-visual-viewport-inset-top`, and every panel anchored at the top moves
|
|
110
|
+
down by as much of it as goes past the host's `--ag-ui-viewport-inset-top`.
|
|
111
|
+
`--ag-ui-keyboard-inset-top` outranks that, as `--ag-ui-keyboard-inset` does
|
|
112
|
+
at the bottom; `0px` opts out.
|
|
113
|
+
|
|
114
|
+
The same panel with a bar reserved at the top also ran past the bottom of the
|
|
115
|
+
visible area by the bar's height whenever a keyboard was up, pan or no pan:
|
|
116
|
+
the measured height replaced the host's box rather than being cut from it, so
|
|
117
|
+
the bar stayed in the position and left the height. The height is now the
|
|
118
|
+
host's box cut to the visible area.
|
|
119
|
+
|
|
120
|
+
At the deepest pan, the one that shows a composer docked at the foot of the
|
|
121
|
+
screen, the panel still went back to the top of the page at full height. The
|
|
122
|
+
element read the page's height from `innerHeight`, which iOS Safari reports
|
|
123
|
+
less the pan for as long as the pan lasts; at that depth it equals the visible
|
|
124
|
+
height, so the element took the two viewports to agree and withdrew its
|
|
125
|
+
measurements. The band below the visible area came out as nothing at any pan
|
|
126
|
+
too, leaving a bottom-anchored panel behind the keyboard. The page's height
|
|
127
|
+
is now read from the root element's `clientHeight`, which an iPhone reported
|
|
128
|
+
unchanged through the pan.
|
|
129
|
+
|
|
130
|
+
- **A full-screen panel no longer runs under Safari's bars with no keyboard
|
|
131
|
+
up.** Where nothing has been measured, the panel's height fell back to
|
|
132
|
+
`100vh`, which iOS Safari resolves to the screen with its bars collapsed, so
|
|
133
|
+
on a page that never scrolls them away the foot of the panel sat under the
|
|
134
|
+
address bar: 40px on the iPhone measured, with a docked composer in it. The
|
|
135
|
+
fallback is now `100dvh`, the screen with the bars as they are.
|
|
136
|
+
|
|
137
|
+
- **An element removed from the document and inserted again is one element.**
|
|
138
|
+
Every insertion built the chrome again into the same shadow root, so a
|
|
139
|
+
re-inserted `<ag-ui-chat>` had two headers, two composers, a second set of
|
|
140
|
+
resize grips, and the conversation drawn a second time beneath the first. The
|
|
141
|
+
listeners on its long-lived parts were added again too:
|
|
142
|
+
- one click on Stop cancelled the run three times;
|
|
143
|
+
- one press of the built-in theme toggle flipped it twice, so it appeared to
|
|
144
|
+
do nothing;
|
|
145
|
+
- a dropped or pasted file was added twice;
|
|
146
|
+
- one arrow press moved the launcher two steps.
|
|
147
|
+
|
|
148
|
+
With `data-threads-url`, a second remote store wrapped the first, so every
|
|
149
|
+
rename and delete reached the server twice. Frameworks do this without being
|
|
150
|
+
asked (a portal, a keyed list, a move between containers), and removing and
|
|
151
|
+
re-inserting is the documented way to apply a connect-time attribute written
|
|
152
|
+
late.
|
|
153
|
+
|
|
154
|
+
Connecting now builds the chrome in place of the last connection's, and ties
|
|
155
|
+
every listener on a long-lived part to the connection, so leaving the document
|
|
156
|
+
removes them. The upload tray and the mic are mounted afresh. The thread store
|
|
157
|
+
is wrapped once, and a `data-threads-url` removed while detached takes its
|
|
158
|
+
remote store away. The transcript is rebuilt from history, as `reload()`
|
|
159
|
+
rebuilds it. The composer's recall history is kept. Re-inserting still applies
|
|
160
|
+
the attributes as they stand when the element comes back. A host that called
|
|
161
|
+
`offerQuoteInPage()` calls it again after re-inserting, as before.
|
|
162
|
+
|
|
10
163
|
## [0.39.0] — 2026-09-17
|
|
11
164
|
|
|
12
165
|
### Changed
|
|
@@ -3973,7 +4126,8 @@ hosts that both arrange the page the way it expects.
|
|
|
3973
4126
|
### Notes
|
|
3974
4127
|
- First release — exercising the automated npm OIDC publish pipeline end-to-end.
|
|
3975
4128
|
|
|
3976
|
-
[Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.
|
|
4129
|
+
[Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.40.0...HEAD
|
|
4130
|
+
[0.40.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.39.0...v0.40.0
|
|
3977
4131
|
[0.39.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.38.0...v0.39.0
|
|
3978
4132
|
[0.38.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.37.0...v0.38.0
|
|
3979
4133
|
[0.37.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.36.0...v0.37.0
|
package/README.md
CHANGED
|
@@ -253,6 +253,11 @@ The list: `data-attachments-url`, `data-attachment-accept`, `data-attachment-max
|
|
|
253
253
|
`data-skills-url`, `data-skills`, `data-prompt-chips`, `data-slash-commands`, `data-theme-toggle`,
|
|
254
254
|
`data-strings`, `data-icon-url`.
|
|
255
255
|
|
|
256
|
+
What re-inserting costs: the chrome is built again from the attributes as they stand, a run in
|
|
257
|
+
progress is cancelled, and the conversation is redrawn from its stored history — the same rebuild
|
|
258
|
+
`reload()` performs, and the reason that method exists for a host that can only configure the
|
|
259
|
+
element after the fact.
|
|
260
|
+
|
|
256
261
|
**Properties** (JS only, not attributes): `headers`, `getHeaders`, `trustedOrigins`, `allowImages`,
|
|
257
262
|
`autoConfirm`, `confirmPredicate`, `askUser`, `askUserRenderer`, `approvalRenderer`,
|
|
258
263
|
`approveWithEdits`, `agentFactory`, `getTools`, `getContext`, `routeMap`, `navigate`, `getPageMap`,
|
|
@@ -300,10 +305,13 @@ the `copyCode` / `copied` / `copyFailed` strings.
|
|
|
300
305
|
|
|
301
306
|
`sendMessage(content, attachments?)` sends as if the user had typed it — user bubble,
|
|
302
307
|
`ag-ui-submit` event, run started. Use it for an "Ask about this order" button, a command
|
|
303
|
-
palette, or a composer of your own replacing the built-in one. It no-ops
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
308
|
+
palette, or a composer of your own replacing the built-in one. It no-ops for an entirely
|
|
309
|
+
empty message, and while a run — or a checkpoint continuation picked from the panel — is in
|
|
310
|
+
flight; a continuation counts from the pick, not from its first event, so the gap where two
|
|
311
|
+
runs could start against one conversation is closed. Unlike the built-in Send it does **not**
|
|
312
|
+
queue, so your composer keeps what it tried to send, and it does **not** consult the
|
|
313
|
+
attachment tray: what you pass is what is sent, so your composer stays in charge of its own
|
|
314
|
+
state.
|
|
307
315
|
|
|
308
316
|
`attachFile(file)` queues a file into the tray exactly as the picker and drag-and-drop do, with
|
|
309
317
|
the same validation and progress chip. It returns `false` when uploads are not configured
|
|
@@ -869,6 +877,13 @@ chat.askUserRenderer = (request, { signal }) =>
|
|
|
869
877
|
myModal.ask(request.question, request.options, { allowCustom: request.allowCustom, signal });
|
|
870
878
|
```
|
|
871
879
|
|
|
880
|
+
**A renderer that throws or rejects falls back to the built-in card** for that call, with a
|
|
881
|
+
`console.warn` naming the tool call. As with `approvalRenderer`, the renderer decides how the
|
|
882
|
+
question looks, not whether it is asked, so the run carries on as if no renderer were set. The one
|
|
883
|
+
exception is a rejection after the signal fired, which is how a renderer is expected to honour Stop:
|
|
884
|
+
that wait resolves with an empty answer, as the built-in card does on the same signal, with no card
|
|
885
|
+
and no warning.
|
|
886
|
+
|
|
872
887
|
### DOM-driver and animation primitives
|
|
873
888
|
|
|
874
889
|
So the agent can visibly drive the host page, the package ships generic, framework-free
|
|
@@ -1082,7 +1097,10 @@ chat.addEventListener("ag-ui-toggle", (e) => console.log(e.detail.collapsed));
|
|
|
1082
1097
|
### The composer's own keys
|
|
1083
1098
|
|
|
1084
1099
|
**Enter during a run queues.** A second run cannot start while one is in flight —
|
|
1085
|
-
it would orphan the first — so that key used to do nothing at all, silently.
|
|
1100
|
+
it would orphan the first — so that key used to do nothing at all, silently. A
|
|
1101
|
+
checkpoint continuation picked from the panel counts as in flight from the pick
|
|
1102
|
+
rather than from its first event, which is a request later, so a turn typed in
|
|
1103
|
+
that gap is parked too rather than racing it. What
|
|
1086
1104
|
is waiting shows above the composer as chips, each of which takes its message
|
|
1087
1105
|
back when pressed, and the next one is sent when the run settles. Stopping the
|
|
1088
1106
|
run discards them: sending into a conversation someone has just stopped is the
|
|
@@ -2384,6 +2402,12 @@ Picking a row with an empty composer says so above the input and puts the caret
|
|
|
2384
2402
|
there, rather than closing the panel over nothing: a continuation sends **only**
|
|
2385
2403
|
the new turn, so with nothing typed there is nothing to send.
|
|
2386
2404
|
|
|
2405
|
+
Picking a row while an answer is still streaming — the conversation's own, or
|
|
2406
|
+
another continuation's — is refused the same way: the hint asks you to wait or
|
|
2407
|
+
stop it, and what you typed stays in the composer for the pick after. The run in
|
|
2408
|
+
flight is not cancelled for you, since a continuation starting over it would
|
|
2409
|
+
leave two answers streaming into one transcript with Stop reaching only one.
|
|
2410
|
+
|
|
2387
2411
|
### One URL, three endpoints
|
|
2388
2412
|
|
|
2389
2413
|
`data-runs-url` is the only thing to configure. `resume/<id>/` and `fork/<id>/`
|
|
@@ -2401,7 +2425,7 @@ The component satisfies that structurally rather than by remembering a rule. A
|
|
|
2401
2425
|
continuation runs on its own short-lived agent, built pointing at the resume
|
|
2402
2426
|
endpoint and seeded with **no** history — so "only the new turn" is the only
|
|
2403
2427
|
thing it *can* send, and the fresh run id comes free because a new agent mints
|
|
2404
|
-
one.
|
|
2428
|
+
one. Nothing of the conversation's history goes out on its request.
|
|
2405
2429
|
|
|
2406
2430
|
A resumed run is a normal run in every other respect: frontend tools execute,
|
|
2407
2431
|
approval interrupts render their card, `headers` are re-read per request so
|
|
@@ -2411,9 +2435,14 @@ a rotated CSRF token or JWT still reaches the endpoint, it carries and updates
|
|
|
2411
2435
|
construction as the conversation's own, differing only in the endpoint and the
|
|
2412
2436
|
empty seed.
|
|
2413
2437
|
|
|
2414
|
-
|
|
2415
|
-
the answer, and a store keeps one message list per thread, so
|
|
2416
|
-
|
|
2438
|
+
The continued exchange joins the conversation. Its agent holds only the new turn
|
|
2439
|
+
and the answer, and a store keeps one message list per thread, so each save
|
|
2440
|
+
writes the conversation as it stood when you picked the row with the exchange
|
|
2441
|
+
after it — through the same `saveMessages` as any other run, and as far as it
|
|
2442
|
+
got if it was stopped. A reload then replays the exchange, and the next message
|
|
2443
|
+
you send, now to `endpoint` again, carries it together with the shared state the
|
|
2444
|
+
continuation left. What is saved is what the transcript shows: a fork's exchange
|
|
2445
|
+
follows the conversation it was picked from, in that same thread.
|
|
2417
2446
|
|
|
2418
2447
|
If the index can't be reached, the panel shows its empty state rather than an
|
|
2419
2448
|
error — a history affordance that fails is empty, not broken.
|
|
@@ -2745,6 +2774,12 @@ of the screen with a frame drawn round it.
|
|
|
2745
2774
|
`embedded` is left alone deliberately: it sits in a box you sized and placed, and
|
|
2746
2775
|
only you know whether that column should become the whole screen.
|
|
2747
2776
|
|
|
2777
|
+
The [greeting layout](#the-greeting-on-an-empty-page) changes shape here too, and
|
|
2778
|
+
it is the one part of this that `embedded` gets as well, because it moves nothing
|
|
2779
|
+
about the box you placed: an empty conversation keeps its composer at the foot of
|
|
2780
|
+
the panel, with the starters against it and the greeting over the space above
|
|
2781
|
+
them, instead of centring all three together.
|
|
2782
|
+
|
|
2748
2783
|
The corner placements still rest at their launcher, so a full-bleed panel is
|
|
2749
2784
|
something the user opens rather than something they are given.
|
|
2750
2785
|
|
|
@@ -2831,11 +2866,25 @@ widget measures the hidden band and publishes it as
|
|
|
2831
2866
|
`--ag-ui-visual-viewport-inset-bottom`; state this one instead to outrank that
|
|
2832
2867
|
measurement, or set it to `0px` to opt out of the lift entirely.
|
|
2833
2868
|
|
|
2869
|
+
`--ag-ui-keyboard-inset-top` does the same at the top. To show a field a
|
|
2870
|
+
keyboard would cover, a mobile browser pans the visible area down the page, and
|
|
2871
|
+
a panel anchored to the screen (`page`, `full`, `side`, `sidebar`, and at phone
|
|
2872
|
+
width the corner placements too) moves down with it. An `embedded` panel renders
|
|
2873
|
+
in your own box rather than against the screen, so it does not move at any width.
|
|
2874
|
+
The widget publishes the pan as `--ag-ui-visual-viewport-inset-top`, and the
|
|
2875
|
+
panel moves by as much of it as goes past your `--ag-ui-viewport-inset-top`,
|
|
2876
|
+
since the pan scrolls a reserved bar away with the page. State
|
|
2877
|
+
`--ag-ui-keyboard-inset-top` to outrank that distance, or `0px` to keep the
|
|
2878
|
+
panel below your reserved top.
|
|
2879
|
+
|
|
2834
2880
|
`--ag-ui-viewport-height` and `--ag-ui-viewport-width` state the usable box
|
|
2835
2881
|
outright, for the case where no viewport-percentage length describes it. An
|
|
2836
2882
|
on-screen keyboard is the one that matters: it changes neither `vh` nor `dvh` nor
|
|
2837
2883
|
`svh` on any current mobile browser, so a full-bleed panel has to be told the
|
|
2838
|
-
visual viewport's height rather than deriving it.
|
|
2884
|
+
visual viewport's height rather than deriving it. The widget does that itself;
|
|
2885
|
+
where it has nothing to report, the panel falls back to `100dvh` rather than
|
|
2886
|
+
`100vh`, because iOS Safari resolves `vh` to the screen with its bars collapsed
|
|
2887
|
+
and a panel sized from it runs under them.
|
|
2839
2888
|
|
|
2840
2889
|
Marks are variables too, so one vocabulary covers a re-theme rather than
|
|
2841
2890
|
leaving half the transcript in the built-in set: `--ag-ui-tool-icon-done` /
|
|
@@ -2961,7 +3010,7 @@ component sets, so a new one cannot ship undocumented.
|
|
|
2961
3010
|
| Typed question | `question`, `question-body`, `question-options`, `question-choice`, `question-choice-text`, `question-radio`, `question-input`, `question-actions`, `question-button` |
|
|
2962
3011
|
| Composer | `composer`, `composer-surface`, `composer-tools`, `input`, `send`, `attach-button`, `voice-button` |
|
|
2963
3012
|
| Attachments | `attachment-tray`, `attachment-chips` (the read-only chips on sent bubbles), and the shared chip parts `attachment-chip`, `attachment-chip-icon`, `attachment-chip-name`, `attachment-chip-size`, `attachment-chip-bar`, `attachment-chip-bar-fill`, `attachment-chip-retry`, `attachment-chip-remove` |
|
|
2964
|
-
| Skills | `skill-chips`, `skill-chip`, `skill-palette`, `skill-item`, `skill-item-title`, `skill-item-desc`, `skill-item-token`, `skill-hint` (the composer hint: a skill’s missing placeholders, and a run continuation with nothing typed) |
|
|
3013
|
+
| Skills | `skill-chips`, `skill-chip`, `skill-palette`, `skill-item`, `skill-item-title`, `skill-item-desc`, `skill-item-token`, `skill-hint` (the composer hint: a skill’s missing placeholders, and a run continuation picked with nothing typed or while a run is in flight) |
|
|
2965
3014
|
| Thread drawer | `drawer`, `drawer-backdrop`, `drawer-panel`, `drawer-header`, `drawer-title`, `drawer-new`, `drawer-close`, `drawer-filter`, `drawer-list`, `drawer-empty`, `drawer-row`, `drawer-row-select`, `drawer-row-title`, `drawer-row-time`, `drawer-row-preview`, `drawer-row-actions`, `drawer-row-rename`, `drawer-row-delete`, `drawer-rename-input`, `drawer-confirm`, `drawer-confirm-label`, `drawer-confirm-yes`, `drawer-confirm-no` |
|
|
2966
3015
|
| Charts | `chart-block`, `chart-title`, `chart-legend` |
|
|
2967
3016
|
| Checkpoints panel | `checkpoints`, `checkpoints-header`, `checkpoints-title`, `checkpoints-list`, `checkpoints-empty`, `checkpoint-row`, `checkpoint-label`, `checkpoint-time`, `checkpoint-id`, `checkpoint-branch`, `checkpoint-action` (plus `checkpoint-resume`, `checkpoint-fork`) |
|
|
@@ -3050,7 +3099,8 @@ naturally with the [answer well](#the-answer-well).
|
|
|
3050
3099
|
#### The greeting on an empty page
|
|
3051
3100
|
|
|
3052
3101
|
Until the first message is sent, a page shows a greeting with the composer centred beneath it,
|
|
3053
|
-
and the composer moves to the foot of the page once the conversation has something in it.
|
|
3102
|
+
and the composer moves to the foot of the page once the conversation has something in it. On a
|
|
3103
|
+
phone it starts at the foot, for the reason below.
|
|
3054
3104
|
|
|
3055
3105
|
```html
|
|
3056
3106
|
<ag-ui-chat endpoint="/agent/" placement="page" user-name="Ada"></ag-ui-chat>
|
|
@@ -3071,6 +3121,14 @@ and the composer moves to the foot of the page once the conversation has somethi
|
|
|
3071
3121
|
restores the plain layout there. `embedded` opts in with `data-greeting` (any value but `off`),
|
|
3072
3122
|
for an app shell that gives the panel a page-sized box. The corner placements and the sidebar
|
|
3073
3123
|
never show it: a panel opened from a launcher is already mid-task.
|
|
3124
|
+
- **On a phone** the composer stays at the foot, the starters (or your own `empty` content) sit
|
|
3125
|
+
against it, and the greeting takes the middle of what they leave — the middle of the
|
|
3126
|
+
transcript when there are none. Centring is a shape for a screen with room to spare; at
|
|
3127
|
+
[600px wide and below](#small-viewports) the room is what the on-screen keyboard takes, and a
|
|
3128
|
+
composer centred over an empty band sits halfway up what is left of the screen, with the
|
|
3129
|
+
prompts that start a conversation nowhere near the field that sends one.
|
|
3130
|
+
`data-small-viewport="off"` keeps the centred shape at every width, as it keeps the rest of
|
|
3131
|
+
the desktop layout.
|
|
3074
3132
|
|
|
3075
3133
|
The composer's rows stay centred while you type, while a draft grows and while attachments are
|
|
3076
3134
|
added, because the centring is two equal flexible halves either side of them and growth splits
|