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
2 changes: 2 additions & 0 deletions design-system/packages/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,8 @@ Compact tabs use `size="sm"` (30px, 14px icons, 4px icon gap); standard tabs ret

Dialog titles use 24px bold type with their own 29px line box and normal tracking. `DialogHeader` and `DialogFooter` omit separators by default; pass `separator` for a deliberate divider. A direct `DialogBody` sibling of `DialogFooter appearance="floating"` owns the trailing scroll inset automatically. The floating footer provides the 68px centered action area and a masked blur/gradient using the current theme surface; reduced transparency and forced colors use an opaque fallback. Keep scrollable form content inside `DialogBody` instead of adding a second viewport with independent footer spacing.

`ConfirmDialog secondaryActionPlacement="start"` presents an alternative action as a text button at the start of the footer, with cancel and confirm grouped at the end. The groups wrap when space is limited, keeping cancel and confirm together. The default `inline` placement retains the standard action order and outline secondary button.

Extra-large (`xl`) dialogs have an 800px maximum width and continue shrinking within the viewport gutter. Provider editing uses the floating footer; small workspace creation retains its attached footer and existing button/input sizes. The Lab workspace pattern uses local sample paths and callbacks only.

Keep `Dialog` and `Sheet` mounted and set `open={false}` to close them. They retain the last committed children during the exit animation, with interaction disabled, so clearing an owner selection does not collapse the surface. Reopening uses the latest children and cancels the pending exit. Owners that conditionally mount an editor can remove it in `onExitComplete`, which runs once after the surface unmounts.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const confirmDialogMeta = {
{ defaultValue: "warning", name: "type", type: "info | warning | error | success" },
{ name: "confirmText", type: "ReactNode" },
{ name: "secondaryText", type: "ReactNode" },
{ defaultValue: "inline", name: "secondaryActionPlacement", type: "inline | start" },
{ name: "cancelText", type: "ReactNode" },
{ name: "preview", type: "ReactNode" },
{ defaultValue: "false", name: "confirmDanger", type: "boolean" },
Expand Down Expand Up @@ -42,5 +43,8 @@ export const confirmDialogMeta = {
"layout.confirmDialog.previewRadius",
"type.body.md.fontSize",
"type.code.sm.fontSize",
"space.2",
"space.3",
"space.4",
],
} as const satisfies ComponentMeta;
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
.messageRow,
.icon,
.message,
.preview {
.preview,
.splitActions,
.actionGroup {
box-sizing: border-box;
}

Expand Down Expand Up @@ -93,6 +95,25 @@
overflow-wrap: anywhere;
}

.splitActions {
display: flex;
min-inline-size: 0;
inline-size: 100%;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
column-gap: var(--openbitfun-space-4);
row-gap: var(--openbitfun-space-3);
}

.actionGroup {
display: flex;
flex: 0 0 auto;
align-items: center;
gap: var(--openbitfun-space-2);
margin-inline-start: auto;
}

@media (forced-colors: active) {
.icon {
color: CanvasText;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export interface ConfirmDialogProps {
open: boolean;
pendingAction?: "confirm" | "secondary" | null;
preview?: ReactNode;
/** Place an alternative action at the start, separate from cancel and confirm. */
secondaryActionPlacement?: "inline" | "start";
secondaryText?: ReactNode;
showCancel?: boolean;
showCloseButton?: boolean;
Expand Down Expand Up @@ -75,6 +77,7 @@ export const ConfirmDialog = forwardRef<HTMLDivElement, ConfirmDialogProps>(
open,
pendingAction: controlledPendingAction,
preview,
secondaryActionPlacement = "inline",
secondaryText,
showCancel = true,
showCloseButton = false,
Expand All @@ -91,6 +94,8 @@ export const ConfirmDialog = forwardRef<HTMLDivElement, ConfirmDialogProps>(
const resolvedIcon = icon === false ? null : icon ?? defaultIcons[type];
const hasMessage = message !== undefined && message !== null && message !== "";
const hasPreview = preview !== undefined && preview !== null && preview !== "";
const hasSecondary = secondaryText !== undefined && secondaryText !== null;
const secondaryAtStart = hasSecondary && secondaryActionPlacement === "start";
const resolvedCancelText = cancelText ?? designSystem.messages.confirmCancel;
const resolvedConfirmText = confirmText ?? designSystem.messages.confirmAction;

Expand Down Expand Up @@ -125,6 +130,35 @@ export const ConfirmDialog = forwardRef<HTMLDivElement, ConfirmDialogProps>(
onOpenChange(false, reason);
}, [busy, onOpenChange]);

const cancelButton = showCancel ? (
<Button disabled={busy} onClick={() => requestClose("cancel-button")} variant="fill">
{resolvedCancelText}
</Button>
) : null;
const secondaryButton = hasSecondary ? (
<Button
disabled={busy}
labelBehavior={secondaryAtStart ? "static" : undefined}
loading={pendingAction === "secondary"}
onClick={() => void runAction("secondary", onSecondary)}
variant={secondaryAtStart ? "text" : "outline"}
>
{secondaryText}
</Button>
) : null;
const confirmButton = (
<Button
disabled={busy}
loading={pendingAction === "confirm"}
onClick={() => void runAction("confirm", onConfirm)}
ref={confirmButtonRef}
tone={confirmDanger || type === "error" ? "danger" : "neutral"}
variant="primary"
>
{resolvedConfirmText}
</Button>
);

return (
<Dialog
closeOnEscape={!busy && closeOnEscape}
Expand Down Expand Up @@ -186,31 +220,29 @@ export const ConfirmDialog = forwardRef<HTMLDivElement, ConfirmDialogProps>(
</DialogBody>
) : null}
<DialogFooter>
{showCancel ? (
<Button disabled={busy} onClick={() => requestClose("cancel-button")} variant="fill">
{resolvedCancelText}
</Button>
) : null}
{secondaryText !== undefined && secondaryText !== null ? (
<Button
disabled={busy}
loading={pendingAction === "secondary"}
onClick={() => void runAction("secondary", onSecondary)}
variant="outline"
{secondaryAtStart ? (
<div
className={styles.splitActions}
data-openbitfun-component="confirm-dialog"
data-openbitfun-part="actions"
>
{secondaryText}
</Button>
) : null}
<Button
disabled={busy}
loading={pendingAction === "confirm"}
onClick={() => void runAction("confirm", onConfirm)}
ref={confirmButtonRef}
tone={confirmDanger || type === "error" ? "danger" : "neutral"}
variant="primary"
>
{resolvedConfirmText}
</Button>
{secondaryButton}
<div
className={styles.actionGroup}
data-openbitfun-component="confirm-dialog"
data-openbitfun-part="actionGroup"
>
{cancelButton}
{confirmButton}
</div>
</div>
) : (
<>
{cancelButton}
{secondaryButton}
{confirmButton}
</>
)}
</DialogFooter>
</Dialog>
);
Expand Down
47 changes: 24 additions & 23 deletions src/crates/assembly/core/src/agentic/coordination/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11311,7 +11311,7 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
snapshot.parent_agent_type.clone(),
snapshot.build_child_session_config(None),
Some(format!("session-{}", snapshot.parent_session_id)),
SessionKind::Standard,
SessionKind::EphemeralChild,
)
.await?;
self.session_manager
Expand Down Expand Up @@ -21722,7 +21722,7 @@ mod tests {
}

#[tokio::test]
async fn btw_session_persists_relationship_and_seeds_forked_listing_baselines() {
async fn btw_session_is_ephemeral_and_seeds_forked_listing_baselines() {
let (coordinator, session_manager) = test_persistent_coordinator();
// The parent lives in a registered remote workspace; the child must
// inherit that record's SSH facts rather than transport hints.
Expand Down Expand Up @@ -21811,7 +21811,7 @@ mod tests {

assert_eq!(
child_session.kind,
crate::agentic::core::SessionKind::Standard
crate::agentic::core::SessionKind::EphemeralChild
);
assert_eq!(
child_session.last_user_dialog_agent_type.as_deref(),
Expand Down Expand Up @@ -21871,26 +21871,27 @@ mod tests {
let metadata = session_manager
.load_session_metadata(&session_storage_path, &child_session.session_id)
.await
.expect("BTW metadata should load")
.expect("BTW metadata should exist");
let relationship = metadata
.relationship
.expect("BTW relationship should persist");
assert_eq!(relationship.kind, Some(SessionRelationshipKind::Btw));
assert_eq!(
relationship.parent_session_id.as_deref(),
Some(parent_session.session_id.as_str())
);
assert_eq!(
relationship.parent_request_id.as_deref(),
Some("btw-request")
);
assert_eq!(
relationship.parent_dialog_turn_id.as_deref(),
Some("parent-turn")
);
assert_eq!(relationship.parent_turn_index, Some(2));
assert_eq!(metadata.memory_mode, SessionMemoryMode::Disabled);
.expect("BTW metadata lookup should succeed");
assert!(metadata.is_none(), "temporary BTW must not write history");
assert!(!session_manager.should_persist_session_id(&child_session.session_id));

let reused = coordinator
.ensure_btw_session(
&parent_session.session_id,
&child_session.session_id,
None,
"btw-follow-up",
Some("parent-turn"),
Some(2),
)
.await
.expect("temporary BTW should accept follow-up questions");
assert_eq!(reused.kind, SessionKind::EphemeralChild);
assert!(session_manager
.load_session_metadata(&session_storage_path, &child_session.session_id)
.await
.expect("BTW metadata lookup after reuse should succeed")
.is_none());
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,7 @@ impl PersistenceManager {
}
}

async fn build_session_metadata(
pub(super) async fn build_session_metadata(
&self,
workspace_path: &Path,
session: &Session,
Expand Down
Loading
Loading