Skip to content

feat(apollo-react): add the Wind chat composer - #1378

Merged
BenGSchulz merged 1 commit into
feat/wind-chat-tool-call-tree-renderersfrom
feat/wind-chat-composer
Oct 20, 2026
Merged

BenGSchulz merged 1 commit into
feat/wind-chat-tool-call-tree-renderersfrom
feat/wind-chat-composer

Conversation

@BenGSchulz

@BenGSchulz BenGSchulz commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fifth and last PR of the Wind chat renderer stack (MST-16566). The Wind composer placeholder from R-1 is replaced by apollo-wind's ChatComposer, wired to the service as Material's input is.

  • Draft: the composer follows the service prompt (getPrompt at mount, SetPrompt after) and writes edits back with setPrompt; an empty draft clears it, as in Material. SetInputFocused focuses the field.
  • Send:
    • Enter sends and Shift+Enter starts a new line; the primitive leaves IME composition alone.
    • Sending goes through the service Request intercept with the prompt text and the attachments, then clears the draft and the attachments.
    • Focus returns to the field after a send from the button.
    • Sending is held back during the initial skeleton load and while an attachment is still loading.
    • A parity test checks that the Request payload from Wind matches Material's.
  • Stop: while a reply is awaited or streams, the send button stops it, unless disabledFeatures.stopResponse is set, in which case it stays a disabled send button and Enter does not send. Same as Material. The button stays filled in both states (variant="default"), as Material's does; the primitive's ghost stop button faded its fill out on every send and read as a flicker.
  • Attachments (chips sized as Material's: 30px tall, at most half the message, 8px apart, name truncated with the full name as a tooltip only when cut off, on messages and in the composer; a sent message's attachment row is capped to the message so it scrolls inside the panel):
    • They come in through the attach button, a panel-wide DropzoneOverlay drop, and paste anywhere on the panel, checked against allowedAttachments: MIME types and their extensions, max size, and the max count minus what is already attached (maxCount: 0 means no limit, as in Material).
    • Paste is handled by Wind with apollo-wind's validateFiles: it takes over the paste only when a file passes, so text pasted alongside a refused file still lands, and the refused file is named in the error.
    • While the panel cannot take files (attachments disabled, no composer, chat closing), a file dropped on it is still caught so the browser does not open it in the tab.
    • Removing a chip while the host uploads it publishes SetAttachments with it in removed and drops it from the draft; finishing the upload never brings it back, so the remove button stays available while uploading.
    • Chips use the file type icons from the message list, show as uploading while the service marks them loading, and can be removed.
    • The attach button lists the limits in a tooltip and to screen readers, as Material's does.
    • Hidden, and drops ignored, when disabledFeatures.attachments is set.
    • Chip sizing: on messages the cap is calc(50cqw - 4px) against the message content (an @container), not a percentage of the row. A user message's row is end-aligned and sizes itself to its chips, so a percentage of it squeezed a lone chip to half its own width. With Material's 8px gap, two capped chips fill the message exactly; the composer row uses the same 8px gap (overriding the primitive's 12px).
    • Alignment: a user message's row sits at the message's trailing edge while its chips fit (justify-end-safe) and starts from the leading edge once it overflows, so the whole row stays reachable by scrolling. Reply rows stay start-aligned.
  • Errors and footer:
    • The service error (error or warn) shows above the field as ChatComposerError (role="alert"), rendered as markdown like Material's, and dismissing it clears the error and keeps focus in the field.
    • The footer disclaimer comes from the shared useChatLabels at 10px, as in Material, hidden with disabledFeatures.footer.
  • Compact and read-only:
    • spacing.compactMode sets the composer's compact density, and spacing.promptBox sets the textarea rows.
    • Read-only hides the composer, as R-1 already did and as Material does.

Hoisted into src/chat/headless

Helper What it carries Material change
hooks/use-attachment-intake.ts: useAttachmentIntake, getAcceptedFileTypes Material's dropzone rules and messages: one file at a time when multiple is off, the whole batch refused when over maxCount, oversized and wrongly typed files named, the rest parsed and attached, the error cleared when nothing was refused. Takes neutral rejection reasons, so both react-dropzone and apollo-wind's checks feed it dropzone.tsx maps react-dropzone codes onto it (its own handling removed)
hooks/use-composer-send.ts: useComposerSend In-flight state, whether stop is allowed, send (ending dictation first) and stop chat-input.tsx submit uses it
hooks/use-attachment-intake.ts: checkAttachmentFiles Picked files checked as the drop targets check them: type by MIME or extension, size, then the count left chat-input-actions.tsx attach button now validates types, size and count through it and the intake hook, like the dropzone (its size message is now the dropzone's)
hooks/use-attachment-limits.ts: useAttachmentLimits The attach limits text (max files, max size, allowed types) chat-input-actions.tsx tooltip and screen-reader description

Storybook

pnpm storybook:design, then Apollo React / Chat / Playground, Compare renderers:

  • Attachments (chips sized as Material's: 30px tall, at most half the message, 8px apart, name truncated with the full name as a tooltip only when cut off, on messages and in the composer; a sent message's attachment row is capped to the message so it scrolls inside the panel): a user turn with files, then a draft with an attachment placed in both composers through setPrompt. Attach more with the button, by dropping files on the panel, or by pasting.
  • Error and Warning: the alert above the composer, with markdown and a dismiss button.
  • autoReply echo or stream: send from either composer. The message mirrors to the other chat and both reply. Stop while streaming, or turn on disableStopResponse to see a disabled send button instead.
  • compactMode: the compact composer.
  • disableAttachments, disableFooter, inputPlaceholder and footerDisclaimer.

Tests

  • vitest --run src/chat src/material/components/ap-chat src/material/components/ap-tool-call: 49 files, 280 tests pass. New tests cover:
    • the intake rules: accepted plus named rejections, the whole batch refused when over the count, one file at a time, the accept list;
    • the composer:
      • Enter and Shift+Enter;
      • focus after send;
      • following the service prompt;
      • stop, and stop disabled;
      • the error alert as markdown, with warn and dismiss;
      • picked files sent with the prompt;
      • an oversized file named;
      • drop and paste on the panel;
      • attachments disabled;
      • compact and the footer;
      • chips capped against the message width with an 8px gap, in messages and the composer;
      • a user message's row end-aligned, a reply's not;
    • the Request payload parity test against Material.
  • tsc --noEmit: clean.
  • Known gap (W-10): apollo-wind's DropzoneOverlay takes a single hint string, so Wind's drop overlay cannot list the max count, size and types as Material's does. Composer chips also take no title or tooltip from the primitive, so the truncation tooltip is a native title.
  • biome check on touched files: clean.
  • New strings, in en.json only: input.label ("Message", the field's accessible name) and input.error.dismiss ("Dismiss"). Everything else reuses Material's ids with Material's source messages.

Stack

  1. R-1 Wind shell: feat(apollo-react): add the Wind chat renderer shell #1371
  2. R-2 message list: feat(apollo-react): add the Wind chat message list #1372
  3. R-3 markdown renderer: feat(apollo-react): add the Wind chat markdown renderer #1375
  4. R-4 tool-call and tree renderers: feat(apollo-react): add the Wind chat tool-call and tree renderers #1376
  5. R-5 composer: this PR
  6. R-6 first run, suggestions and thinking state: feat(apollo-react): add the Wind chat first run, suggestions and thinking state #1396
  7. R-7 history and settings: feat(apollo-react): add the Wind chat history and settings panels #1397
  8. R-8 CSS delivery and docs: feat(apollo-react): document the Wind chat setup and its delivery #1399

Jira: MST-16566

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Apollo Coded App preview deployments are ready.

Project Status Preview Updated (PT)
apollo-design Ready Preview · Logs Oct 15, 2026, 03:54:09 PM
apollo-docs Ready Preview · Logs Oct 15, 2026, 03:54:09 PM
apollo-landing Ready Preview · Logs Oct 15, 2026, 03:54:09 PM
apollo-vertex Ready Preview · Logs Oct 15, 2026, 03:54:09 PM

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Dependency License Review

  • ✅ 1947 package(s) scanned
  • ✅ No license issues found
  • ⚠️ 2 package(s) excluded (see details below)
License distribution
License Packages
MIT 1713
ISC 91
Apache-2.0 56
BSD-3-Clause 28
BSD-2-Clause 23
BlueOak-1.0.0 8
MPL-2.0 4
MIT-0 3
CC0-1.0 3
MIT OR Apache-2.0 2
(MIT OR Apache-2.0) 2
Unlicense 2
LGPL-3.0-or-later 1
Python-2.0 1
CC-BY-4.0 1
(MPL-2.0 OR Apache-2.0) 1
Unknown 1
Artistic-2.0 1
(WTFPL OR MIT) 1
(BSD-2-Clause OR MIT OR Apache-2.0) 1
CC-BY-3.0 1
0BSD 1
(MIT OR CC0-1.0) 1
MIT AND ISC 1
Excluded packages
Package Version License Reason
@img/sharp-libvips-linux-x64 1.3.4 LGPL-3.0-or-later LGPL pre-built binary, not linked
khroma 2.1.0 Unknown MIT per GitHub repo, missing license field in package.json

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

📊 Coverage + size by package

Per-package coverage and bundle size on this PR. New-line coverage = of the source lines this PR adds or changes, the % hit by tests.

Package Coverage New-line coverage Packed (gzip) Unpacked vs main
@uipath/apollo-core — — 42.02 MB 50.17 MB ±0
@uipath/apollo-react 56.1% 93.2% (179/192) 8.02 MB 31.61 MB +35.1 KB
@uipath/apollo-ui-icons — — 2.86 MB 6.97 MB ±0
@uipath/apollo-vertex — — — — —
@uipath/apollo-wind — — 785.2 KB 4.55 MB +18 B
@uipath/ap-chat 85.8% — 40.37 MB 45.58 MB +2.0 KB

"Coverage" is each package's own coverage.include scope (e.g. apollo-core instruments only scripts/). "Packed"/"Unpacked" come from npm pack --dry-run and only cover built packages — "—" means not measured this run (package not affected / not built). "vs main" is the packed (gzipped) delta against the last successful main build (the package-sizes artifact from the Release workflow); "—" there means no main baseline was available this run. The baseline is main's latest build, not this PR's exact merge-base, so it includes any drift since the branch diverged. Packages with no vitest config are omitted.

Copilot AI balanced review requested due to automatic review settings October 15, 2026 22:46
@BenGSchulz
BenGSchulz force-pushed the feat/wind-chat-composer branch from 8da30e9 to c1d906e Compare October 15, 2026 22:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added the size:XXL 1,000+ changed lines. label Oct 15, 2026
@BenGSchulz
BenGSchulz marked this pull request as ready for review October 16, 2026 15:55
Copilot AI balanced review requested due to automatic review settings October 16, 2026 16:10
@BenGSchulz
BenGSchulz force-pushed the feat/wind-chat-composer branch from c1d906e to 7a16f6e Compare October 16, 2026 16:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions
github-actions Bot temporarily deployed to preview/apollo-vertex October 16, 2026 16:11 Destroyed
@github-actions
github-actions Bot temporarily deployed to preview/apollo-landing October 16, 2026 16:11 Destroyed
@github-actions
github-actions Bot temporarily deployed to preview/apollo-design October 16, 2026 16:11 Destroyed
@github-actions
github-actions Bot temporarily deployed to preview/apollo-docs October 16, 2026 16:11 Destroyed
Replace the Wind composer placeholder with apollo-wind's ChatComposer
wired to the service as Material's input is: the draft follows the
service prompt, Enter or the send button sends through the Request
intercept with the attachments and returns focus to the field, the send
button stops an in-flight reply unless stopResponse is disabled, the
service error shows above the field as a dismissible markdown alert, and
the footer disclaimer comes from the shared labels. Attachments come in
through the attach button and a panel-wide DropzoneOverlay (drop and
paste), checked against allowedAttachments.

Hoist Material's dropzone validation and messages into
useAttachmentIntake and its send and stop logic into useComposerSend,
and switch Material's dropzone and input to them.

MST-16566

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@BenGSchulz
BenGSchulz force-pushed the feat/wind-chat-composer branch from 7a16f6e to be7fcd3 Compare October 16, 2026 19:52
Copilot AI balanced review requested due to automatic review settings October 16, 2026 19:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions
github-actions Bot temporarily deployed to preview/apollo-vertex October 16, 2026 19:53 Destroyed
@github-actions
github-actions Bot temporarily deployed to preview/apollo-design October 16, 2026 19:53 Destroyed
@github-actions
github-actions Bot temporarily deployed to preview/apollo-docs October 16, 2026 19:53 Destroyed
@github-actions
github-actions Bot temporarily deployed to preview/apollo-landing October 16, 2026 19:53 Destroyed

@CalinaCristian CalinaCristian left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One functionality discrepancy in the storybook for composer vs material:

Screen.Recording.2026-10-20.at.3.40.23.AM.mov
Screen.Recording.2026-10-20.at.3.41.03.AM.mov

In material, we don't allow same attachment twice.
Also, when in compact mode I see no difference for the wind component in the attachments section.

@BenGSchulz

Copy link
Copy Markdown
Contributor Author

One functionality discrepancy in the storybook for composer vs material:

In material, we don't allow same attachment twice. Also, when in compact mode I see no difference for the wind component in the attachments section.

Thanks for catching that. The gaps in compact mode are known and will be addressed via #1403. I will make sure to cover the duplicate attachments in the follow-up to those.

@BenGSchulz
BenGSchulz merged commit 6a00ac2 into main Oct 20, 2026
49 of 81 checks passed
@BenGSchulz
BenGSchulz deleted the feat/wind-chat-composer branch October 20, 2026 15:46

This branch was successfully deployed

No deployments
preview/apollo-landing — be7fcd33 Deployed Oct 16, 2026 by github-actions[bot]
preview/apollo-docs — be7fcd33 Deployed Oct 16, 2026 by github-actions[bot]
preview/apollo-vertex — be7fcd33 Deployed Oct 16, 2026 by github-actions[bot]
preview/apollo-design — be7fcd33 Deployed Oct 16, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pkg:apollo-react size:XXL 1,000+ changed lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants