Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions ai/transcript.ml
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,11 @@ let rendered_body cfg fallback item_s =
| Some view -> view
| None -> fallback item_s

let content_row cfg body =
row ~main:`center ~grow:1.0 ~min_width:0
[ column ~grow:1.0 ~max_width:cfg.content_width ~min_width:0
~cross:`stretch ~padding_horizontal:8 ~padding_vertical:4 [ body ] ]

let grouped_item cfg (item_s : item Signal.signal) : t =
scoped (fun _context ->
let item = sample item_s in
Expand Down Expand Up @@ -279,7 +284,7 @@ let tool_group cfg (row_s : row Signal.signal) : t =
in
Signal.set open_ (Some (not current))
in
accordion
content_row cfg (accordion
~text:(reactive
(fun (items : item list) (active : bool) ->
let n = List.length items in
Expand All @@ -292,7 +297,7 @@ let tool_group cfg (row_s : row Signal.signal) : t =
~accessibility_identifier:"lui-ai-tool-group"
[ column ~cross:`stretch ~gap:6
[ keyed ~source:items_s ~key:(fun (i : item) -> i.id)
~cmp:String.compare ~mount:(grouped_item cfg) ] ])
~cmp:String.compare ~mount:(grouped_item cfg) ] ]))

let builtin_body cfg context (item_s : item Signal.signal) : t =
ignore context;
Expand All @@ -315,9 +320,7 @@ let item_row_of cfg context (item_s : item Signal.signal) : t =
?style_class:
(match cfg.item_class item with "" -> None | s -> Some s)
~data_attrs:(reactive cfg.item_data_attrs item_s)
[ row ~main:`center ~grow:1.0
[ column ~grow:1.0 ~max_width:cfg.content_width ~cross:`stretch
~padding_horizontal:8 ~padding_vertical:4 [ body ] ] ]
[ content_row cfg body ]

let row_of cfg (row_s : row Signal.signal) : t =
scoped (fun context ->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Bounded Tool Group Layout

## Problem

Mapre's actual browser consumer shows a completed tool-group summary spanning
1160px while ordinary message content is bounded to 768px. The transcript's
Tool_group path bypasses the centered content column used by Single rows.

## Proposal

Give grouped tools the same centered bounded content surface as messages while
keeping the outer scroll viewport full width. Share the static layout helper
between Single and Tool_group, preserve host renderers, keyed child identity,
reactive metadata and disclosure state. Do not add app-specific CSS, vendor a
copy, alter Dune files or add another scroll owner.

## Alternatives considered

### Constrain the scroll viewport

Rejected because it recreates ignored wheel input in blank conversation gutters.

### Override the consumer with layout CSS

Rejected because the generic transcript already owns content_width and must
apply it consistently across row kinds and platforms.

## Acceptance criteria

- Native mounted grouped-only transcripts respect an explicit non-default
content_width and include centered content layout; the case fails first.
- Existing host-rendering, streaming, keyed lifetime, disclosure and transcript
tests pass. The outer viewport still grows across the conversation pane.
- The actual Mapre browser consumer has bounded centered activity, accessible
disclosure and stable host details on desktop and mobile.
- Submit the upstream PR and consume an installed reviewed package; no vendoring.

## Risks

- Group summaries gain the same horizontal/vertical padding as message content;
disclosure height changes must retain the host's scroll anchoring behavior.

## Questions

None. This completes the existing transcript layout contract and the user's
explicit request to fix shared LUI issues upstream before consumer integration.

## Verification

The new grouped-only mounted native case fails before the fix because no
centered/bounded content node exists. It now passes with a non-default 560px
content_width; all 25 AI cases and all 148 native test_lui cases pass. Melange
and install targets compile. The helper is shared with ordinary message rows;
no scroll viewport, event handler, public signature or dependency changes.
The consumer's desktop browser first reports an unbounded 1160px summary.
Final installed-package consumer acceptance remains pending; this decision
stays proposed until that actual browser proof is complete.
15 changes: 15 additions & 0 deletions test/test_lui_ai.ml
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,20 @@ let test_bounded_layout () =
ignore bounded;
drive_dispose s

let test_group_bounded_layout () =
let view _ctx source _send =
Lui_ai.Transcript.transcript ~content_width:560 ~messages:source () in
let s = drive_mount
~initial:[ tool_item "t1" `completed;
tool_item "t2" `completed ] ~view in
ignore (find_node s (fun n ->
n.Drive.Model.kind = "row"
&& node_prop n "main" = Some (StringValue "center")));
ignore (find_node s (fun n ->
n.Drive.Model.kind = "column"
&& node_prop n "max-width" = Some (IntValue 560)));
drive_dispose s

let test_container_data_attrs_signal () =
let attrs_ref = ref None in
let view _ctx model_s _send =
Expand Down Expand Up @@ -653,6 +667,7 @@ let tests =
[ Alcotest.test_case "grouped tail key" `Quick test_grouped_tail_key;
Alcotest.test_case "grouped pin" `Quick test_grouped_pin;
Alcotest.test_case "bounded layout" `Quick test_bounded_layout;
Alcotest.test_case "group bounded layout" `Quick test_group_bounded_layout;
Alcotest.test_case "container attrs signal" `Quick
test_container_data_attrs_signal;
Alcotest.test_case "streaming updates same row" `Quick
Expand Down
Loading