basalt-ui 1.28.0 → 1.29.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/AGENTS.md +11 -18
- package/CHANGELOG.md +13 -0
- package/MIGRATING.md +151 -7
- package/README.md +23 -66
- package/agent/rules/basalt-batteries.md +59 -182
- package/agent/rules/basalt-charts.md +56 -75
- package/agent/rules/basalt-controls.md +38 -69
- package/agent/rules/basalt-mantine.md +58 -103
- package/agent/rules/basalt-state.md +42 -60
- package/agent/rules/basalt-tokens.md +46 -67
- package/agent/skills/basalt-app/SKILL.md +2 -0
- package/agent/templates/CLAUDE-block.md.tpl +14 -14
- package/configs/oxlint-plugin.js +70 -167
- package/configs/oxlint-plugin.test.ts +20 -186
- package/configs/oxlint.json +0 -1
- package/dist/agent/ai-sdk-transport.d.ts.map +1 -1
- package/dist/agent/ai-sdk-transport.js +7 -4
- package/dist/agent/coalesce.js +1 -1
- package/dist/agent/merge.js +1 -1
- package/dist/agent/transport.d.ts +13 -2
- package/dist/agent/transport.d.ts.map +1 -1
- package/dist/agent/use-agent-thread-runs.d.ts +12 -1
- package/dist/agent/use-agent-thread-runs.d.ts.map +1 -1
- package/dist/agent/use-agent-thread-runs.js +20 -6
- package/dist/agent-chat/index.d.ts +1 -1
- package/dist/agent-chat/index.d.ts.map +1 -1
- package/dist/agent-chat/relative-time.js +1 -1
- package/dist/agent-chat/thread-detail-panel.js +1 -1
- package/dist/agent-chat/thread-feed-row.d.ts +32 -7
- package/dist/agent-chat/thread-feed-row.d.ts.map +1 -1
- package/dist/agent-chat/thread-feed-row.js +121 -86
- package/dist/agent-chat/thread-feed.d.ts +11 -1
- package/dist/agent-chat/thread-feed.d.ts.map +1 -1
- package/dist/agent-chat/thread-feed.js +10 -6
- package/dist/agent-chat/thread-message.js +1 -1
- package/dist/agent-chat/virtualize.d.ts +39 -0
- package/dist/agent-chat/virtualize.d.ts.map +1 -1
- package/dist/agent-chat/virtualize.js +15 -0
- package/dist/charts/index.d.ts +3 -3
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +8 -4
- package/dist/charts/kinds/BandStrip.js +1 -1
- package/dist/charts/kinds/Bars.d.ts +1 -3
- package/dist/charts/kinds/Bars.d.ts.map +1 -1
- package/dist/charts/kinds/Bars.js +1 -1
- package/dist/charts/kinds/DualPanel.d.ts +3 -1
- package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
- package/dist/charts/kinds/DualPanel.js +1 -1
- package/dist/charts/kinds/StackedArea.js +1 -1
- package/dist/charts/kinds/ZonedLine.d.ts +1 -3
- package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
- package/dist/charts/primitives/Axes.d.ts +21 -2
- package/dist/charts/primitives/Axes.d.ts.map +1 -1
- package/dist/charts/primitives/Axes.js +34 -2
- package/dist/charts/primitives/ChartCard.d.ts +20 -4
- package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
- package/dist/charts/primitives/ChartCard.js +62 -33
- package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
- package/dist/charts/primitives/ChartFrame.js +8 -1
- package/dist/charts/primitives/ChartPending.d.ts +12 -6
- package/dist/charts/primitives/ChartPending.d.ts.map +1 -1
- package/dist/charts/primitives/ChartPending.js +1 -1
- package/dist/charts/utils/format.d.ts +5 -92
- package/dist/charts/utils/format.d.ts.map +1 -1
- package/dist/charts/utils/format.js +10 -80
- package/dist/cli/audit-allows.d.ts +24 -0
- package/dist/cli/audit-allows.d.ts.map +1 -0
- package/dist/cli/audit-allows.js +240 -0
- package/dist/cli/check-theme.d.ts +10 -0
- package/dist/cli/check-theme.d.ts.map +1 -0
- package/dist/cli/check-theme.js +139 -0
- package/dist/cli/doctor.d.ts +47 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +197 -0
- package/dist/cli/guard-hook.d.ts +9 -0
- package/dist/cli/guard-hook.d.ts.map +1 -0
- package/dist/cli/guard-hook.js +93 -0
- package/dist/cli/help.d.ts +9 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +53 -0
- package/dist/cli/index.d.ts +360 -270
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +85 -1901
- package/dist/cli/init.d.ts +4 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +165 -0
- package/dist/cli/sync.d.ts +43 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +206 -0
- package/dist/cli/tokens-css.d.ts +51 -0
- package/dist/cli/tokens-css.d.ts.map +1 -0
- package/dist/cli/tokens-css.js +165 -0
- package/dist/commands/define-commands.js +1 -1
- package/dist/commands/define-overlays.js +1 -1
- package/dist/commands/index.d.ts +2 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +6 -0
- package/dist/commands/overlays-mount.d.ts +7 -9
- package/dist/commands/overlays-mount.d.ts.map +1 -1
- package/dist/commands/shell-bridge.d.ts +57 -0
- package/dist/commands/shell-bridge.d.ts.map +1 -0
- package/dist/commands/shell-bridge.js +32 -0
- package/dist/common/errors.d.ts +35 -0
- package/dist/common/errors.d.ts.map +1 -1
- package/dist/common/errors.js +29 -1
- package/dist/common/index.d.ts +2 -0
- package/dist/common/index.d.ts.map +1 -1
- package/dist/common/index.js +6 -0
- package/dist/common/is-dev.d.ts.map +1 -0
- package/dist/{motion/index.d.ts → common/motion.d.ts} +1 -1
- package/dist/common/motion.d.ts.map +1 -0
- package/dist/common/props.d.ts +1 -1
- package/dist/common/props.d.ts.map +1 -1
- package/dist/common/validate.js +1 -1
- package/dist/content/markdown.d.ts +3 -4
- package/dist/content/markdown.d.ts.map +1 -1
- package/dist/content/markdown.js +1 -4
- package/dist/controls/actions.d.ts +1 -1
- package/dist/controls/actions.d.ts.map +1 -1
- package/dist/controls/panel-row.js +1 -1
- package/dist/controls/range-filter.js +1 -1
- package/dist/dashboard/delta-badge.d.ts +18 -10
- package/dist/dashboard/delta-badge.d.ts.map +1 -1
- package/dist/dashboard/delta-badge.js +33 -1
- package/dist/dashboard/empty-state.d.ts +1 -4
- package/dist/dashboard/empty-state.d.ts.map +1 -1
- package/dist/dashboard/empty-state.js +1 -2
- package/dist/dashboard/index.d.ts +4 -2
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +7 -1
- package/dist/dashboard/query-state.d.ts +4 -13
- package/dist/dashboard/query-state.d.ts.map +1 -1
- package/dist/dashboard/query-state.js +4 -7
- package/dist/{section → dashboard}/section.d.ts +2 -2
- package/dist/{section → dashboard}/section.d.ts.map +1 -1
- package/dist/{section → dashboard}/section.js +2 -2
- package/dist/dashboard/settings-section.d.ts +1 -1
- package/dist/dashboard/settings-section.d.ts.map +1 -1
- package/dist/dashboard/settings-section.js +1 -1
- package/dist/dashboard/stat-card.d.ts +1 -1
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/dashboard/stat-card.js +1 -1
- package/dist/dashboard/widget-header.d.ts.map +1 -0
- package/dist/data/data-table.js +2 -2
- package/dist/data/table.d.ts +1 -1
- package/dist/data/table.d.ts.map +1 -1
- package/dist/data/table.js +2 -16
- package/dist/data/virtual.d.ts +3 -3
- package/dist/dev-dock.d.ts +28 -0
- package/dist/dev-dock.d.ts.map +1 -0
- package/dist/dev-dock.js +85 -0
- package/dist/format/date.d.ts +62 -0
- package/dist/format/date.d.ts.map +1 -0
- package/dist/format/date.js +106 -0
- package/dist/format/index.d.ts +39 -0
- package/dist/format/index.d.ts.map +1 -0
- package/dist/format/index.js +54 -0
- package/dist/format/measure.d.ts +15 -0
- package/dist/format/measure.d.ts.map +1 -0
- package/dist/format/measure.js +16 -0
- package/dist/format/number.d.ts +69 -0
- package/dist/format/number.d.ts.map +1 -0
- package/dist/format/number.js +62 -0
- package/dist/format/shared.d.ts +27 -0
- package/dist/format/shared.d.ts.map +1 -0
- package/dist/format/shared.js +29 -0
- package/dist/forms/field.d.ts +4 -20
- package/dist/forms/field.d.ts.map +1 -1
- package/dist/forms/field.js +0 -4
- package/dist/forms/form-layout.d.ts +1 -1
- package/dist/forms/form-layout.d.ts.map +1 -1
- package/dist/forms/form-layout.js +1 -1
- package/dist/forms/index.d.ts +1 -1
- package/dist/forms/index.d.ts.map +1 -1
- package/dist/forms/index.js +1 -2
- package/dist/forms/use-form-submit.js +1 -1
- package/dist/guard/index.d.ts +2 -9
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +16 -26
- package/dist/guard/types.d.ts +8 -10
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/index.d.ts +16 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -29
- package/dist/notifications/index.d.ts +5 -5
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +0 -2
- package/dist/notifications/mount-guard.d.ts.map +1 -1
- package/dist/notifications/mount-guard.js +2 -2
- package/dist/provider/connectivity-indicator.d.ts.map +1 -0
- package/dist/{connectivity → provider}/connectivity-provider.d.ts +1 -1
- package/dist/provider/connectivity-provider.d.ts.map +1 -0
- package/dist/{connectivity/types.d.ts → provider/connectivity-types.d.ts} +1 -1
- package/dist/provider/connectivity-types.d.ts.map +1 -0
- package/dist/provider/error-fallback.module.css +21 -0
- package/dist/provider/error-fallback.module.css.d.ts +9 -0
- package/dist/provider/index.d.ts +20 -36
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +42 -32
- package/dist/provider/lab-theme.js +1 -1
- package/dist/provider/use-connectivity.d.ts +3 -0
- package/dist/provider/use-connectivity.d.ts.map +1 -0
- package/dist/query-client.d.ts +63 -0
- package/dist/query-client.d.ts.map +1 -0
- package/dist/query-client.js +33 -0
- package/dist/{query/devtools.d.ts → query-devtools.d.ts} +2 -2
- package/dist/query-devtools.d.ts.map +1 -0
- package/dist/register.d.ts +17 -3
- package/dist/register.d.ts.map +1 -1
- package/dist/router-tanstack/index.d.ts +4 -7
- package/dist/router-tanstack/index.d.ts.map +1 -1
- package/dist/router-tanstack/index.js +1 -9
- package/dist/router-tanstack/nav.d.ts +1 -1
- package/dist/router-tanstack/nav.d.ts.map +1 -1
- package/dist/router-tanstack/search-store.d.ts +3 -6
- package/dist/router-tanstack/search-store.d.ts.map +1 -1
- package/dist/router-tanstack/use-nav.d.ts +1 -1
- package/dist/router-tanstack/use-nav.d.ts.map +1 -1
- package/dist/shell/app-breadcrumbs.d.ts +1 -1
- package/dist/shell/app-breadcrumbs.d.ts.map +1 -1
- package/dist/shell/app-main.module.css +11 -0
- package/dist/shell/app-mobile-nav.d.ts +1 -1
- package/dist/shell/app-mobile-nav.d.ts.map +1 -1
- package/dist/shell/app-mobile-nav.js +24 -2
- package/dist/shell/app-sidebar.d.ts +1 -1
- package/dist/shell/app-sidebar.d.ts.map +1 -1
- package/dist/shell/app-sidebar.js +31 -2
- package/dist/shell/app-sidebar.module.css +10 -0
- package/dist/shell/index.d.ts +10 -4
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +13 -17
- package/dist/shell/mobile-nav-model.d.ts +1 -1
- package/dist/shell/mobile-nav-model.d.ts.map +1 -1
- package/dist/{nav/types.d.ts → shell/nav-types.d.ts} +1 -1
- package/dist/shell/nav-types.d.ts.map +1 -0
- package/dist/shell/page-aside.d.ts.map +1 -1
- package/dist/shell/page-aside.js +2 -29
- package/dist/shell/page-title.d.ts +14 -0
- package/dist/shell/page-title.d.ts.map +1 -0
- package/dist/shell/page-title.js +25 -0
- package/dist/shell/page-title.module.css +33 -0
- package/dist/shell/page-title.module.css.d.ts +11 -0
- package/dist/shell/sidebar-block-model.d.ts +1 -1
- package/dist/shell/sidebar-block-model.d.ts.map +1 -1
- package/dist/shell/sidebar-blocks.d.ts +1 -1
- package/dist/shell/sidebar-blocks.d.ts.map +1 -1
- package/dist/shell/use-breakpoint.d.ts +11 -0
- package/dist/shell/use-breakpoint.d.ts.map +1 -0
- package/dist/shell/use-breakpoint.js +33 -0
- package/dist/state/fields.d.ts +3 -19
- package/dist/state/fields.d.ts.map +1 -1
- package/dist/state/fields.js +6 -16
- package/dist/styles.css +36 -0
- package/dist/surfaces.d.ts +18 -41
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +46 -59
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/{theme-toggle/index.d.ts → theme/theme-toggle.d.ts} +1 -1
- package/dist/theme/theme-toggle.d.ts.map +1 -0
- package/dist/{theme-toggle/index.js → theme/theme-toggle.js} +1 -1
- package/dist/tokens/index.d.ts +1 -0
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +10 -0
- package/dist/tokens/palette.d.ts +12 -0
- package/dist/tokens/palette.d.ts.map +1 -1
- package/dist/tokens/palette.js +13 -1
- package/dist/tokens.css +1 -0
- package/llms.txt +9 -24
- package/package.json +12 -16
- package/src/agent/ai-sdk-transport.ts +11 -4
- package/src/agent/coalesce.ts +1 -1
- package/src/agent/merge.ts +1 -1
- package/src/agent/transport.ts +15 -2
- package/src/agent/use-agent-thread-runs.ts +65 -15
- package/src/agent-chat/index.ts +6 -4
- package/src/agent-chat/relative-time.ts +1 -1
- package/src/agent-chat/thread-detail-panel.tsx +1 -1
- package/src/agent-chat/thread-feed-row.tsx +105 -30
- package/src/agent-chat/thread-feed.tsx +51 -25
- package/src/agent-chat/thread-message.tsx +1 -1
- package/src/agent-chat/virtualize.ts +48 -0
- package/src/charts/index.ts +7 -10
- package/src/charts/kinds/BandStrip.tsx +1 -1
- package/src/charts/kinds/Bars.tsx +2 -5
- package/src/charts/kinds/DualPanel.tsx +4 -3
- package/src/charts/kinds/StackedArea.tsx +1 -1
- package/src/charts/kinds/ZonedLine.tsx +1 -4
- package/src/charts/primitives/Axes.tsx +49 -0
- package/src/charts/primitives/ChartCard.tsx +49 -6
- package/src/charts/primitives/ChartFrame.tsx +5 -1
- package/src/charts/primitives/ChartPending.tsx +14 -8
- package/src/charts/utils/format.ts +17 -186
- package/src/cli/audit-allows.ts +371 -0
- package/src/cli/check-theme.ts +197 -0
- package/src/cli/doctor.ts +331 -0
- package/src/cli/guard-hook.ts +115 -0
- package/src/cli/help.ts +101 -0
- package/src/cli/index.ts +269 -3439
- package/src/cli/init.ts +247 -0
- package/src/cli/sync.ts +324 -0
- package/src/cli/tokens-css.ts +252 -0
- package/src/commands/define-commands.ts +1 -1
- package/src/commands/define-overlays.ts +1 -1
- package/src/commands/index.ts +10 -1
- package/src/commands/overlays-mount.tsx +8 -10
- package/src/commands/shell-bridge.ts +86 -0
- package/src/common/errors.ts +70 -0
- package/src/common/index.ts +2 -0
- package/src/common/props.ts +1 -1
- package/src/common/validate.ts +1 -1
- package/src/content/markdown.tsx +4 -8
- package/src/controls/actions.tsx +1 -1
- package/src/controls/panel-row.tsx +1 -1
- package/src/controls/range-filter.tsx +1 -1
- package/src/dashboard/delta-badge.tsx +74 -7
- package/src/dashboard/empty-state.tsx +2 -6
- package/src/dashboard/index.ts +11 -2
- package/src/dashboard/query-state.tsx +5 -18
- package/src/{section → dashboard}/section.tsx +4 -4
- package/src/dashboard/settings-section.tsx +2 -2
- package/src/dashboard/stat-card.tsx +2 -2
- package/src/data/data-table.tsx +3 -3
- package/src/data/table.ts +6 -25
- package/src/data/virtual-list.tsx +1 -1
- package/src/data/virtual.ts +3 -3
- package/src/dev-dock.tsx +159 -0
- package/src/format/date.ts +184 -0
- package/src/format/index.ts +69 -0
- package/src/format/measure.ts +31 -0
- package/src/format/number.ts +129 -0
- package/src/format/shared.ts +63 -0
- package/src/forms/field.ts +4 -24
- package/src/forms/form-layout.tsx +2 -2
- package/src/forms/index.ts +1 -2
- package/src/forms/use-form-submit.ts +1 -1
- package/src/guard/index.ts +30 -56
- package/src/guard/types.ts +7 -10
- package/src/index.ts +38 -29
- package/src/notifications/index.ts +5 -7
- package/src/notifications/mount-guard.ts +7 -9
- package/src/{connectivity → provider}/connectivity-indicator.tsx +1 -1
- package/src/{connectivity → provider}/connectivity-provider.tsx +1 -1
- package/src/provider/error-fallback.module.css +21 -0
- package/src/provider/error-fallback.module.css.d.ts +9 -0
- package/src/provider/index.tsx +71 -71
- package/src/provider/lab-theme.ts +1 -1
- package/src/{connectivity → provider}/use-connectivity.ts +3 -3
- package/src/query-client.ts +100 -0
- package/src/{query/devtools.tsx → query-devtools.tsx} +5 -4
- package/src/register.ts +20 -4
- package/src/router-tanstack/index.ts +4 -15
- package/src/router-tanstack/nav.ts +1 -1
- package/src/router-tanstack/search-store.ts +3 -4
- package/src/router-tanstack/use-nav.ts +1 -1
- package/src/shell/app-breadcrumbs.tsx +1 -1
- package/src/shell/app-main.module.css +11 -0
- package/src/shell/app-mobile-nav.tsx +28 -1
- package/src/shell/app-sidebar.module.css +10 -0
- package/src/shell/app-sidebar.tsx +31 -2
- package/src/shell/index.tsx +23 -28
- package/src/shell/mobile-nav-model.ts +1 -1
- package/src/shell/page-aside.tsx +2 -52
- package/src/shell/page-title.module.css +33 -0
- package/src/shell/page-title.module.css.d.ts +11 -0
- package/src/shell/page-title.tsx +57 -0
- package/src/shell/sidebar-block-model.ts +1 -1
- package/src/shell/sidebar-blocks.tsx +1 -1
- package/src/shell/use-breakpoint.ts +73 -0
- package/src/state/fields.ts +7 -43
- package/src/styles.css +36 -0
- package/src/surfaces.ts +45 -60
- package/src/theme/index.ts +7 -0
- package/src/{theme-toggle/index.tsx → theme/theme-toggle.tsx} +1 -1
- package/src/tokens/index.ts +10 -0
- package/src/tokens/palette.ts +12 -0
- package/dist/connectivity/connectivity-indicator.d.ts.map +0 -1
- package/dist/connectivity/connectivity-provider.d.ts.map +0 -1
- package/dist/connectivity/index.d.ts +0 -14
- package/dist/connectivity/index.d.ts.map +0 -1
- package/dist/connectivity/index.js +0 -8
- package/dist/connectivity/types.d.ts.map +0 -1
- package/dist/connectivity/use-connectivity.d.ts +0 -3
- package/dist/connectivity/use-connectivity.d.ts.map +0 -1
- package/dist/data/index.d.ts +0 -38
- package/dist/data/index.d.ts.map +0 -1
- package/dist/data/index.js +0 -24
- package/dist/motion/index.d.ts.map +0 -1
- package/dist/nav/types.d.ts.map +0 -1
- package/dist/notifications/overlay.d.ts +0 -20
- package/dist/notifications/overlay.d.ts.map +0 -1
- package/dist/notifications/overlay.js +0 -14
- package/dist/query/devtools.d.ts.map +0 -1
- package/dist/query/error-message.d.ts +0 -41
- package/dist/query/error-message.d.ts.map +0 -1
- package/dist/query/error-message.js +0 -30
- package/dist/query/index.d.ts +0 -47
- package/dist/query/index.d.ts.map +0 -1
- package/dist/query/index.js +0 -56
- package/dist/router-tanstack/field.d.ts +0 -14
- package/dist/router-tanstack/field.d.ts.map +0 -1
- package/dist/router-tanstack/field.js +0 -4
- package/dist/router-tanstack/multi-search-param-store.d.ts +0 -43
- package/dist/router-tanstack/multi-search-param-store.d.ts.map +0 -1
- package/dist/router-tanstack/multi-search-param-store.js +0 -30
- package/dist/router-tanstack/search-param-store.d.ts +0 -42
- package/dist/router-tanstack/search-param-store.d.ts.map +0 -1
- package/dist/router-tanstack/search-param-store.js +0 -25
- package/dist/section/index.d.ts +0 -2
- package/dist/section/index.d.ts.map +0 -1
- package/dist/section/index.js +0 -4
- package/dist/theme-toggle/index.d.ts.map +0 -1
- package/dist/utils/is-dev.d.ts.map +0 -1
- package/dist/widget-header/delta-badge.d.ts +0 -19
- package/dist/widget-header/delta-badge.d.ts.map +0 -1
- package/dist/widget-header/delta-badge.js +0 -36
- package/dist/widget-header/index.d.ts +0 -3
- package/dist/widget-header/index.d.ts.map +0 -1
- package/dist/widget-header/index.js +0 -8
- package/dist/widget-header/widget-header.d.ts.map +0 -1
- package/src/connectivity/index.ts +0 -19
- package/src/data/index.ts +0 -69
- package/src/notifications/overlay.tsx +0 -66
- package/src/query/error-message.ts +0 -70
- package/src/query/index.ts +0 -97
- package/src/router-tanstack/field.ts +0 -36
- package/src/router-tanstack/multi-search-param-store.ts +0 -106
- package/src/router-tanstack/search-param-store.ts +0 -100
- package/src/section/index.ts +0 -1
- package/src/widget-header/delta-badge.tsx +0 -77
- package/src/widget-header/index.ts +0 -10
- /package/dist/{utils → common}/is-dev.d.ts +0 -0
- /package/dist/{utils → common}/is-dev.js +0 -0
- /package/dist/{motion/index.js → common/motion.js} +0 -0
- /package/dist/{section → dashboard}/section.module.css +0 -0
- /package/dist/{section → dashboard}/section.module.css.d.ts +0 -0
- /package/dist/{widget-header → dashboard}/widget-header.d.ts +0 -0
- /package/dist/{widget-header → dashboard}/widget-header.js +0 -0
- /package/dist/{widget-header → dashboard}/widget-header.module.css +0 -0
- /package/dist/{widget-header → dashboard}/widget-header.module.css.d.ts +0 -0
- /package/dist/{connectivity → provider}/connectivity-indicator.d.ts +0 -0
- /package/dist/{connectivity → provider}/connectivity-indicator.js +0 -0
- /package/dist/{connectivity → provider}/connectivity-provider.js +0 -0
- /package/dist/{connectivity/types.js → provider/connectivity-types.js} +0 -0
- /package/dist/{connectivity → provider}/use-connectivity.js +0 -0
- /package/dist/{query/devtools.js → query-devtools.js} +0 -0
- /package/dist/{nav/types.js → shell/nav-types.js} +0 -0
- /package/src/{utils → common}/is-dev.ts +0 -0
- /package/src/{motion/index.ts → common/motion.ts} +0 -0
- /package/src/{section → dashboard}/section.module.css +0 -0
- /package/src/{section → dashboard}/section.module.css.d.ts +0 -0
- /package/src/{widget-header → dashboard}/widget-header.module.css +0 -0
- /package/src/{widget-header → dashboard}/widget-header.module.css.d.ts +0 -0
- /package/src/{widget-header → dashboard}/widget-header.tsx +0 -0
- /package/src/{connectivity/types.ts → provider/connectivity-types.ts} +0 -0
- /package/src/{nav/types.ts → shell/nav-types.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "basalt-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.0",
|
|
4
4
|
"description": "Opinionated framework for Mantine-based React apps — theme, app shell, visx charts, toolchain presets",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"charts",
|
|
@@ -77,6 +77,11 @@
|
|
|
77
77
|
"import": "./dist/guard/index.js",
|
|
78
78
|
"default": "./dist/guard/index.js"
|
|
79
79
|
},
|
|
80
|
+
"./format": {
|
|
81
|
+
"types": "./dist/format/index.d.ts",
|
|
82
|
+
"import": "./dist/format/index.js",
|
|
83
|
+
"default": "./dist/format/index.js"
|
|
84
|
+
},
|
|
80
85
|
"./forms": {
|
|
81
86
|
"types": "./dist/forms/index.d.ts",
|
|
82
87
|
"import": "./dist/forms/index.js",
|
|
@@ -92,21 +97,11 @@
|
|
|
92
97
|
"import": "./dist/notifications/index.js",
|
|
93
98
|
"default": "./dist/notifications/index.js"
|
|
94
99
|
},
|
|
95
|
-
"./query": {
|
|
96
|
-
"types": "./dist/query/index.d.ts",
|
|
97
|
-
"import": "./dist/query/index.js",
|
|
98
|
-
"default": "./dist/query/index.js"
|
|
99
|
-
},
|
|
100
100
|
"./router-tanstack": {
|
|
101
101
|
"types": "./dist/router-tanstack/index.d.ts",
|
|
102
102
|
"import": "./dist/router-tanstack/index.js",
|
|
103
103
|
"default": "./dist/router-tanstack/index.js"
|
|
104
104
|
},
|
|
105
|
-
"./data": {
|
|
106
|
-
"types": "./dist/data/index.d.ts",
|
|
107
|
-
"import": "./dist/data/index.js",
|
|
108
|
-
"default": "./dist/data/index.js"
|
|
109
|
-
},
|
|
110
105
|
"./data/table": {
|
|
111
106
|
"types": "./dist/data/table.d.ts",
|
|
112
107
|
"import": "./dist/data/table.js",
|
|
@@ -147,11 +142,6 @@
|
|
|
147
142
|
"import": "./dist/state.js",
|
|
148
143
|
"default": "./dist/state.js"
|
|
149
144
|
},
|
|
150
|
-
"./connectivity": {
|
|
151
|
-
"types": "./dist/connectivity/index.d.ts",
|
|
152
|
-
"import": "./dist/connectivity/index.js",
|
|
153
|
-
"default": "./dist/connectivity/index.js"
|
|
154
|
-
},
|
|
155
145
|
"./styles.css": "./dist/styles.css",
|
|
156
146
|
"./tokens.css": "./dist/tokens.css",
|
|
157
147
|
"./configs/*": "./configs/*",
|
|
@@ -165,6 +155,7 @@
|
|
|
165
155
|
"scripts": {
|
|
166
156
|
"build": "tsup && tsc -p tsconfig.build.json --emitDeclarationOnly --declarationMap && bun scripts/copy-assets.mjs && bun scripts/gen-tokens-css.mjs && bun scripts/fix-esm-extensions.mjs",
|
|
167
157
|
"typecheck": "tsc --noEmit",
|
|
158
|
+
"check-budgets": "bun scripts/check-budgets.ts",
|
|
168
159
|
"test": "cd ../.. && bun test packages/basalt-ui",
|
|
169
160
|
"pack-test": "bash scripts/pack-test.sh",
|
|
170
161
|
"prepack": "bun run build",
|
|
@@ -179,6 +170,7 @@
|
|
|
179
170
|
"@shikijs/langs": "^4.3.1",
|
|
180
171
|
"@shikijs/themes": "^4.3.1",
|
|
181
172
|
"@tanstack/react-hotkeys": "0.10.0",
|
|
173
|
+
"@tanstack/react-router-devtools": "^1.166.13",
|
|
182
174
|
"@types/bun": "^1.3.14",
|
|
183
175
|
"@types/hast": "^3.0.4",
|
|
184
176
|
"@types/react": "^19.2.17",
|
|
@@ -224,6 +216,7 @@
|
|
|
224
216
|
"@tanstack/react-query": "^5.101.0",
|
|
225
217
|
"@tanstack/react-query-devtools": "^5.101.0",
|
|
226
218
|
"@tanstack/react-router": "^1.170.0",
|
|
219
|
+
"@tanstack/react-router-devtools": "^1.166.13",
|
|
227
220
|
"@tanstack/react-table": ">=8 <9",
|
|
228
221
|
"@tanstack/react-virtual": ">=3.13.26 <4",
|
|
229
222
|
"@visx/axis": "4.0.0",
|
|
@@ -298,6 +291,9 @@
|
|
|
298
291
|
"@tanstack/react-router": {
|
|
299
292
|
"optional": true
|
|
300
293
|
},
|
|
294
|
+
"@tanstack/react-router-devtools": {
|
|
295
|
+
"optional": true
|
|
296
|
+
},
|
|
301
297
|
"@tanstack/react-table": {
|
|
302
298
|
"optional": true
|
|
303
299
|
},
|
|
@@ -395,7 +395,11 @@ export function aiSdkTransport<TPart = AgentPart>(
|
|
|
395
395
|
// diffPart), so a replayed run rewrites in place instead of duplicating — the literal
|
|
396
396
|
// condition this assertion stands for.
|
|
397
397
|
idempotentReplay: true,
|
|
398
|
-
async *stream(
|
|
398
|
+
async *stream(
|
|
399
|
+
input: string,
|
|
400
|
+
signal?: AbortSignal,
|
|
401
|
+
ctx?: { readonly messageId: string },
|
|
402
|
+
): AsyncGenerator<TPart> {
|
|
399
403
|
// Synthesized locally, first — we already know the chat id client-side, so there is no
|
|
400
404
|
// need to wait on the server to hand us a run id (unlike a river-style protocol).
|
|
401
405
|
yield { id: `${chatId}#start`, type: 'start', runId: chatId, resumeToken: chatId } as TPart
|
|
@@ -403,9 +407,12 @@ export function aiSdkTransport<TPart = AgentPart>(
|
|
|
403
407
|
const { httpTransport, readUIMessageStream: readStream } = await resolveAiSdk()
|
|
404
408
|
const userMessage: UIMessage = {
|
|
405
409
|
// This id is what AI SDK's own backend persistence/dedup keys turns hang off — the same
|
|
406
|
-
// idempotency-key cost as basalt's own ChatMessage.id (see mintMessageId's doc)
|
|
407
|
-
//
|
|
408
|
-
|
|
410
|
+
// idempotency-key cost as basalt's own ChatMessage.id (see mintMessageId's doc). Prefer
|
|
411
|
+
// the caller's OWN idempotency key (ctx.messageId — the id useAgentThreadRuns.start()
|
|
412
|
+
// already minted for this turn's ChatMessage) so the two never diverge for one turn; only
|
|
413
|
+
// a caller that omits ctx (useAgentStream, a hand-rolled stream() call) falls back to
|
|
414
|
+
// minting a fresh one here.
|
|
415
|
+
id: ctx?.messageId ?? mintMessageId(),
|
|
409
416
|
role: 'user',
|
|
410
417
|
parts: [{ type: 'text', text: input }],
|
|
411
418
|
}
|
package/src/agent/coalesce.ts
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
* <PartList parts={coalesceParts(parts)} />
|
|
39
39
|
*/
|
|
40
40
|
import type { AgentPart, ReasoningPart, TextPart, ToolCallPart } from './parts'
|
|
41
|
-
import { isDev } from '../
|
|
41
|
+
import { isDev } from '../common/is-dev'
|
|
42
42
|
|
|
43
43
|
type TextLike = TextPart | ReasoningPart
|
|
44
44
|
|
package/src/agent/merge.ts
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* // parts === [{ id: 'p1', type: 'text', text: 'Hello' }]
|
|
30
30
|
*/
|
|
31
31
|
import type { ReasoningPart, TextPart } from './parts'
|
|
32
|
-
import { isDev } from '../
|
|
32
|
+
import { isDev } from '../common/is-dev'
|
|
33
33
|
|
|
34
34
|
type TextLike = TextPart | ReasoningPart
|
|
35
35
|
|
package/src/agent/transport.ts
CHANGED
|
@@ -34,7 +34,7 @@ import type { AgentPart, AgentPartDraft } from './parts'
|
|
|
34
34
|
// ── AgentTransport ────────────────────────────────────────────────────────────
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* The injected transport seam. `stream(input, signal)` returns an async generator of parts.
|
|
37
|
+
* The injected transport seam. `stream(input, signal, ctx)` returns an async generator of parts.
|
|
38
38
|
* Implement this interface for any backend — Eden, fetch-based SSE, AI SDK, or a mock.
|
|
39
39
|
*
|
|
40
40
|
* The default `TPart` is `AgentPartDraft` (not `AgentPart`): transports yield DRAFTS — `id`
|
|
@@ -42,6 +42,15 @@ import type { AgentPart, AgentPartDraft } from './parts'
|
|
|
42
42
|
* part before it is ever accumulated. Pass an explicit `AgentPart` generic when a transport mints
|
|
43
43
|
* its own ids directly (as `aiSdkTransport` does).
|
|
44
44
|
*
|
|
45
|
+
* `ctx.messageId`, when present, is the id `useAgentThreadRuns.start()` already minted for this
|
|
46
|
+
* turn's user `ChatMessage` — the SAME idempotency key `appendMessage`/the backend's dedup keys off
|
|
47
|
+
* of (see `mintMessageId`'s doc). A transport that mints its OWN wire-level message id independent
|
|
48
|
+
* of that (as `aiSdkTransport` used to) forces the consumer to reconcile two ids for one turn; a
|
|
49
|
+
* transport MAY use `ctx.messageId` as its outbound message id instead of minting a fresh one. The
|
|
50
|
+
* param is optional and appended last so an existing two-arg transport keeps compiling unchanged —
|
|
51
|
+
* only `useAgentThreadRuns.start()`/`retry()` pass it; a bare `stream(input, signal)` call (e.g.
|
|
52
|
+
* `useAgentStream`, a hand-rolled caller) omits it and a transport falls back to minting its own.
|
|
53
|
+
*
|
|
45
54
|
* @example
|
|
46
55
|
* // Minimal mock transport for tests / playground:
|
|
47
56
|
* const mockTransport: AgentTransport = {
|
|
@@ -51,7 +60,11 @@ import type { AgentPart, AgentPartDraft } from './parts'
|
|
|
51
60
|
* }
|
|
52
61
|
*/
|
|
53
62
|
export type AgentTransport<TPart = AgentPartDraft, TInput = string> = {
|
|
54
|
-
stream: (
|
|
63
|
+
stream: (
|
|
64
|
+
input: TInput,
|
|
65
|
+
signal?: AbortSignal,
|
|
66
|
+
ctx?: { readonly messageId: string },
|
|
67
|
+
) => AsyncGenerator<TPart>
|
|
55
68
|
/** Optional: resume a previously-started run from its resumeToken (see StartPart). Transports that don't support resumption simply omit this. */
|
|
56
69
|
resume?: (resumeToken: string, signal?: AbortSignal) => AsyncGenerator<TPart>
|
|
57
70
|
}
|
|
@@ -96,6 +96,14 @@ export type UseAgentThreadRunsArgs<TPart = AgentPart> = {
|
|
|
96
96
|
* Required when TPart is not the default AgentPart union.
|
|
97
97
|
*/
|
|
98
98
|
readonly toUserParts?: (input: string) => TPart[]
|
|
99
|
+
/**
|
|
100
|
+
* Called when a turn's stream throws — never for an `AbortError` (an intentional stop()/
|
|
101
|
+
* supersede, not a failure worth surfacing). Fires from the SAME catch branch that sets
|
|
102
|
+
* `onFailureStatus` on the thread, so a caller wanting a toast/notification for a genuine
|
|
103
|
+
* transport error (a 409/503/401, argo's hermes-chat S19) no longer has to wrap every transport
|
|
104
|
+
* call in its own generator to intercept the throw — see `consumeAndFinalize`'s catch block.
|
|
105
|
+
*/
|
|
106
|
+
readonly onError?: (info: { readonly threadId: string; readonly error: unknown }) => void
|
|
99
107
|
}
|
|
100
108
|
|
|
101
109
|
// ── useAgentThreadRuns return type ────────────────────────────────────────────
|
|
@@ -207,6 +215,7 @@ async function consumeAndFinalize<TPart extends PartLike>(args: {
|
|
|
207
215
|
resolveOutcome: OutcomeResolver<TPart>
|
|
208
216
|
setRuns: Dispatch<SetStateAction<Map<string, ThreadRunState<TPart>>>>
|
|
209
217
|
onFailureStatus: ThreadStatus
|
|
218
|
+
onError?: (info: { readonly threadId: string; readonly error: unknown }) => void
|
|
210
219
|
}): Promise<void> {
|
|
211
220
|
const {
|
|
212
221
|
threadId,
|
|
@@ -219,6 +228,7 @@ async function consumeAndFinalize<TPart extends PartLike>(args: {
|
|
|
219
228
|
resolveOutcome,
|
|
220
229
|
setRuns,
|
|
221
230
|
onFailureStatus,
|
|
231
|
+
onError,
|
|
222
232
|
} = args
|
|
223
233
|
let parts: TPart[] = []
|
|
224
234
|
try {
|
|
@@ -314,6 +324,7 @@ async function consumeAndFinalize<TPart extends PartLike>(args: {
|
|
|
314
324
|
next.delete(threadId)
|
|
315
325
|
return next
|
|
316
326
|
})
|
|
327
|
+
onError?.({ threadId, error: err })
|
|
317
328
|
}
|
|
318
329
|
}
|
|
319
330
|
|
|
@@ -435,6 +446,7 @@ export function useAgentThreadRuns<TPart extends PartLike = AgentPart>({
|
|
|
435
446
|
store,
|
|
436
447
|
resolveOutcome,
|
|
437
448
|
toUserParts,
|
|
449
|
+
onError,
|
|
438
450
|
}: UseAgentThreadRunsArgs<TPart>): UseAgentThreadRunsReturn<TPart> {
|
|
439
451
|
const [runs, setRuns] = useState<Map<string, ThreadRunState<TPart>>>(new Map())
|
|
440
452
|
// Mirrors the latest `runs` state every render so stop() (a plain callback, not a render) can
|
|
@@ -442,6 +454,10 @@ export function useAgentThreadRuns<TPart extends PartLike = AgentPart>({
|
|
|
442
454
|
// updater — same mirroring pattern as storeRef/transportRef below.
|
|
443
455
|
const runsRef = useRef(runs)
|
|
444
456
|
runsRef.current = runs
|
|
457
|
+
// Mirrors the latest onError every render (same pattern as storeRef/transportRef) so a stale
|
|
458
|
+
// closure from an earlier render never fires instead of the consumer's current callback.
|
|
459
|
+
const onErrorRef = useRef(onError)
|
|
460
|
+
onErrorRef.current = onError
|
|
445
461
|
|
|
446
462
|
// Refs: mutable per-render state that must not trigger re-renders.
|
|
447
463
|
const controllersRef = useRef<Map<string, AbortController>>(new Map())
|
|
@@ -520,9 +536,12 @@ export function useAgentThreadRuns<TPart extends PartLike = AgentPart>({
|
|
|
520
536
|
// seeing a phantom in-flight turn no controller is driving anymore, and `stop()` on it was a
|
|
521
537
|
// permanent no-op (nothing left in `controllersRef` to abort) — see `stop()`'s own doc. Scoped to
|
|
522
538
|
// exactly the threadIds this pass is aborting (not a blind `runs.clear()`): the mount-reconcile
|
|
523
|
-
// effect below runs AFTER this cleanup completes, in the same synchronous commit
|
|
524
|
-
//
|
|
525
|
-
// together, in declaration order
|
|
539
|
+
// effect below runs AFTER this cleanup completes, in the same synchronous commit — StrictMode's
|
|
540
|
+
// dev-only double-invoke and `<Activity>` hide/show both destroy-then-recreate EVERY mount effect
|
|
541
|
+
// on this fiber together, in declaration order, regardless of each effect's own dep array (this
|
|
542
|
+
// one stays `[]`; the reconcile effect below is `[store.hydrated]` as of R3 — the double-invoke
|
|
543
|
+
// guarantee is about the mount/unmount CYCLE, not per-effect dep memoization) — a resumable
|
|
544
|
+
// thread's reconcile pass registers a FRESH
|
|
526
545
|
// controller and a fresh `runs` entry there, and this teardown must never clobber that. It
|
|
527
546
|
// can't: by the time this cleanup runs, nothing has created a NEW entry for these threadIds yet
|
|
528
547
|
// (that only happens in the reconcile effect, still to come), so scoping to the ids this pass is
|
|
@@ -547,17 +566,37 @@ export function useAgentThreadRuns<TPart extends PartLike = AgentPart>({
|
|
|
547
566
|
[],
|
|
548
567
|
)
|
|
549
568
|
|
|
550
|
-
// Reconcile orphaned in-flight threads
|
|
551
|
-
// 'streaming' after a reload/remount, since controllersRef and `runs` both
|
|
552
|
-
// would otherwise resolve that skeleton. If the transport supports
|
|
553
|
-
// a resumeToken (from a StartPart emitted before the disconnect)
|
|
554
|
-
// from, attempt to reconnect the run instead. Any other case — no
|
|
555
|
-
// user message, or the resume itself failing — falls back to
|
|
556
|
-
// resend prompt instead of an unresolving skeleton (today's
|
|
557
|
-
//
|
|
558
|
-
//
|
|
559
|
-
//
|
|
569
|
+
// Reconcile orphaned in-flight threads once the store is HYDRATED: a persisted thread can be
|
|
570
|
+
// stuck 'pending' or 'streaming' after a reload/remount, since controllersRef and `runs` both
|
|
571
|
+
// start empty — nothing would otherwise resolve that skeleton. If the transport supports
|
|
572
|
+
// resumption and the thread has a resumeToken (from a StartPart emitted before the disconnect)
|
|
573
|
+
// plus a user message to resume from, attempt to reconnect the run instead. Any other case — no
|
|
574
|
+
// resume(), no resumeToken, no user message, or the resume itself failing — falls back to
|
|
575
|
+
// 'interrupted' so the UI renders a resend prompt instead of an unresolving skeleton (today's
|
|
576
|
+
// behavior, unchanged as the fallback path).
|
|
577
|
+
//
|
|
578
|
+
// R3: keyed on `store.hydrated` rather than a bare `[]`-dep effect. `ThreadsStore.hydrated` is
|
|
579
|
+
// always `true` for the localStorage store (createPersistedState resolves synchronously), so this
|
|
580
|
+
// still fires on the very first commit for every consumer that predates this change — no behavior
|
|
581
|
+
// change there. It only matters for an ASYNC store (`createAdapterThreadsStore`): with `[]`, this
|
|
582
|
+
// ran on mount while `store.threads` was still the adapter's empty pre-load snapshot, so every
|
|
583
|
+
// orphaned thread from a previous session was invisible to the sweep — reconcile-after-reload was
|
|
584
|
+
// silently dead for exactly the store shape (server-backed, paginated) that most needs it. Firing
|
|
585
|
+
// again when `hydrated` flips true re-sweeps against the now-real `storeRef.current.threads`.
|
|
586
|
+
//
|
|
587
|
+
// Deliberately NO separate "has this already run" ref here — the sweep is naturally idempotent:
|
|
588
|
+
// a thread only qualifies as orphaned while its status is 'pending'/'streaming' AND it has no
|
|
589
|
+
// live controller, and this effect's own first pass either moves the status off that pair
|
|
590
|
+
// ('interrupted', or eventually 'done'/'error' once the resumed/started run settles) or registers
|
|
591
|
+
// a controller for it synchronously (before the first `await`) — so a second invocation with the
|
|
592
|
+
// SAME `store.hydrated` value (including React 19 StrictMode's dev-only double-invoke of every
|
|
593
|
+
// mount effect, and an `<Activity>` hide/show — see use-agent-thread-runs.wedge.test.tsx) finds
|
|
594
|
+
// nothing left to reconcile except whatever its own sibling invocation genuinely orphaned by
|
|
595
|
+
// aborting an in-flight controller, which is exactly the case that file's (b)/(c) tests require
|
|
596
|
+
// resume() to fire again for. An explicit "ran once" ref would suppress that second, legitimate
|
|
597
|
+
// sweep and reintroduce the F3 wedge for `store.hydrated`-keyed remounts.
|
|
560
598
|
useEffect(() => {
|
|
599
|
+
if (!store.hydrated) return
|
|
561
600
|
for (const thread of storeRef.current.threads) {
|
|
562
601
|
const orphaned =
|
|
563
602
|
(thread.status === 'pending' || thread.status === 'streaming') &&
|
|
@@ -606,10 +645,14 @@ export function useAgentThreadRuns<TPart extends PartLike = AgentPart>({
|
|
|
606
645
|
resolveOutcome,
|
|
607
646
|
setRuns,
|
|
608
647
|
onFailureStatus: 'interrupted',
|
|
648
|
+
onError: (info) => onErrorRef.current?.(info),
|
|
609
649
|
})
|
|
610
650
|
}
|
|
651
|
+
// Only `store.hydrated` — every other read in this body goes through a ref (storeRef,
|
|
652
|
+
// resolveTransport→transportRef/transportsRef, resolveOutcome closed over from the hook's own
|
|
653
|
+
// args) precisely so this effect's re-run trigger is `hydrated` alone. See the doc above.
|
|
611
654
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
612
|
-
}, [])
|
|
655
|
+
}, [store.hydrated])
|
|
613
656
|
|
|
614
657
|
const start = useCallback(
|
|
615
658
|
(threadId: string, input: string): void => {
|
|
@@ -643,7 +686,13 @@ export function useAgentThreadRuns<TPart extends PartLike = AgentPart>({
|
|
|
643
686
|
threadId,
|
|
644
687
|
controller,
|
|
645
688
|
// Namespaced by threadId — same choice, same caveat, as the mount-time resume call above.
|
|
646
|
-
|
|
689
|
+
// ctx.messageId is this turn's OWN idempotency key (userMessage.id, just minted above) —
|
|
690
|
+
// a transport that accepts it (aiSdkTransport) mints its wire-level message with the SAME
|
|
691
|
+
// id instead of a second, unrelated one (R1 — see AgentTransport.stream's doc).
|
|
692
|
+
generator: withPartIds(
|
|
693
|
+
threadId,
|
|
694
|
+
resolvedTransport.stream(input, controller.signal, { messageId: userMessage.id }),
|
|
695
|
+
),
|
|
647
696
|
userMessage,
|
|
648
697
|
controllersRef,
|
|
649
698
|
appendedRef,
|
|
@@ -651,6 +700,7 @@ export function useAgentThreadRuns<TPart extends PartLike = AgentPart>({
|
|
|
651
700
|
resolveOutcome,
|
|
652
701
|
setRuns,
|
|
653
702
|
onFailureStatus: 'error',
|
|
703
|
+
onError: (info) => onErrorRef.current?.(info),
|
|
654
704
|
})
|
|
655
705
|
},
|
|
656
706
|
[resolveOutcome],
|
package/src/agent-chat/index.ts
CHANGED
|
@@ -25,11 +25,13 @@ export type { ThreadFeedRowProps } from './thread-feed-row'
|
|
|
25
25
|
|
|
26
26
|
// ── Shared transcript/row contracts ───────────────────────────────────────────
|
|
27
27
|
// Type-only. Both are named in the PUBLIC props of components exported above
|
|
28
|
-
// (`ThreadTranscriptProps.affordances`, `ThreadFeedRowProps`'s
|
|
29
|
-
//
|
|
30
|
-
//
|
|
28
|
+
// (`ThreadTranscriptProps.affordances`, `ThreadFeedRowProps`'s height union), so a consumer that
|
|
29
|
+
// wants to hold one in a typed variable needs to be able to name it. No runtime export here — the
|
|
30
|
+
// resolution/defaults live inside the components. `RowHeightProps` (B3) is `ThreadFeedRow`'s OWN
|
|
31
|
+
// height contract — a superset of `VirtualizeProps` that also allows `height` without
|
|
32
|
+
// `virtualize` — kept alongside it for the same reason.
|
|
31
33
|
export type { MessageAffordances } from './message-affordances'
|
|
32
|
-
export type { VirtualizeOptions, VirtualizeProps } from './virtualize'
|
|
34
|
+
export type { RowHeightProps, VirtualizeOptions, VirtualizeProps } from './virtualize'
|
|
33
35
|
|
|
34
36
|
// ── ThreadOutcomeCard ─────────────────────────────────────────────────────────
|
|
35
37
|
export { ThreadOutcomeCard } from './thread-outcome-card'
|
|
@@ -28,7 +28,7 @@ import type { AgentPart, AgentThread, StreamStatus } from '../agent'
|
|
|
28
28
|
import { BasaltStickToBottom } from '../agent'
|
|
29
29
|
import { cx } from '../common/props'
|
|
30
30
|
import type { BasaltProps } from '../common/props'
|
|
31
|
-
import { MOTION_SPRING } from '../motion'
|
|
31
|
+
import { MOTION_SPRING } from '../common/motion'
|
|
32
32
|
import { Composer } from './composer'
|
|
33
33
|
import { ThreadTranscript } from './thread-message'
|
|
34
34
|
import { VX } from '../tokens'
|
|
@@ -33,18 +33,20 @@
|
|
|
33
33
|
* />
|
|
34
34
|
*/
|
|
35
35
|
import { Box, Group, Stack, Text, UnstyledButton } from '@mantine/core'
|
|
36
|
-
import type { JSX } from 'react'
|
|
36
|
+
import type { JSX, ReactNode } from 'react'
|
|
37
37
|
import { useState } from 'react'
|
|
38
38
|
import type {
|
|
39
39
|
AgentThread,
|
|
40
|
+
ChatMessage,
|
|
40
41
|
ForeignPart,
|
|
41
42
|
PartRenderer,
|
|
42
43
|
PartRenderers,
|
|
43
44
|
StreamStatus,
|
|
44
45
|
TranscriptPart,
|
|
45
46
|
} from '../agent'
|
|
47
|
+
import { BasaltStickToBottom } from '../agent'
|
|
46
48
|
import { cx } from '../common/props'
|
|
47
|
-
import type { BasaltProps } from '../common/props'
|
|
49
|
+
import type { BasaltProps, SlotStylesProps } from '../common/props'
|
|
48
50
|
import { assertRequiredProps } from '../common/validate'
|
|
49
51
|
import { VX } from '../tokens'
|
|
50
52
|
import type { ComposerProps, ComposerSubmit } from './composer'
|
|
@@ -52,8 +54,8 @@ import { Composer } from './composer'
|
|
|
52
54
|
import type { MessageAffordances } from './message-affordances'
|
|
53
55
|
import { formatRelativeTime } from './relative-time'
|
|
54
56
|
import { ThreadTranscript } from './thread-message'
|
|
55
|
-
import {
|
|
56
|
-
import type { VirtualizeProps } from './virtualize'
|
|
57
|
+
import { resolveRowHeight } from './virtualize'
|
|
58
|
+
import type { RowHeightProps, VirtualizeProps } from './virtualize'
|
|
57
59
|
|
|
58
60
|
/** A minimal, dependency-free chevron — rotates 90deg when expanded (same inline-svg idiom as
|
|
59
61
|
* `composer.tsx`'s `SendGlyph`/`StopGlyph`: no icon-library dependency for a one-off glyph). */
|
|
@@ -106,6 +108,30 @@ type ThreadFeedRowBase = {
|
|
|
106
108
|
readonly expanded: boolean
|
|
107
109
|
/** Called with the thread's id when the header is clicked/activated. */
|
|
108
110
|
readonly onToggle: (id: string) => void
|
|
111
|
+
/**
|
|
112
|
+
* Header title override. Falls back to `thread.outcome?.title ?? 'Untitled thread'` (today's
|
|
113
|
+
* behavior, unchanged) when omitted. For a server-titled thread whose title is never distilled
|
|
114
|
+
* into a basalt `AgentOutcome` (argo's hermes-chat S4 — title/summary/type/pin are server-owned
|
|
115
|
+
* and never guessed client-side), pass it directly instead of forcing an outcome shape onto data
|
|
116
|
+
* that never had one.
|
|
117
|
+
*/
|
|
118
|
+
readonly title?: string
|
|
119
|
+
/** Header summary override, same fallback rule as `title` (`thread.outcome?.summary ?? ''`). */
|
|
120
|
+
readonly summary?: string
|
|
121
|
+
/** Rendered at the START of the header row, before the title/summary stack — a pin icon, a type
|
|
122
|
+
* badge (argo's hermes-chat S5). Absent by default; renders nothing extra when omitted. */
|
|
123
|
+
readonly headerLeft?: ReactNode
|
|
124
|
+
/** Rendered at the END of the header row, before the timestamp and chevron — a collapsed-only
|
|
125
|
+
* streaming indicator (argo's hermes-chat S5). Absent by default; renders nothing extra when
|
|
126
|
+
* omitted. */
|
|
127
|
+
readonly headerRight?: ReactNode
|
|
128
|
+
/**
|
|
129
|
+
* Overrides the transcript source: when provided, the row renders THESE messages instead of
|
|
130
|
+
* reading `thread.messages` directly (argo's hermes-chat S6 — the confirmed transcript is an
|
|
131
|
+
* optimistic-overlay MERGE over the store's messages, not the store's messages verbatim).
|
|
132
|
+
* Defaults to `thread.messages`.
|
|
133
|
+
*/
|
|
134
|
+
readonly messages?: readonly ChatMessage<TranscriptPart>[]
|
|
109
135
|
/** The live (in-flight) assistant turn's parts, when a run is streaming for this thread. */
|
|
110
136
|
readonly liveParts?: readonly TranscriptPart[]
|
|
111
137
|
/** The live run's status — drives the in-progress indicator on the live block. */
|
|
@@ -137,16 +163,29 @@ type ThreadFeedRowBase = {
|
|
|
137
163
|
* `virtualize`/`height` are forwarded straight to the row's `ThreadTranscript`, carrying the same
|
|
138
164
|
* union guard: an inline row holding a very long thread can window it, and doing so REQUIRES a
|
|
139
165
|
* `height` (the transcript then owns a fixed-height scroll node inside the expanded body, instead
|
|
140
|
-
* of the body growing to the thread's full length).
|
|
141
|
-
*
|
|
166
|
+
* of the body growing to the thread's full length). `height` alone (no `virtualize`) is B3's
|
|
167
|
+
* bounded-but-not-virtualized mode — see `RowHeightProps`'s own doc. Omit both and the row's
|
|
168
|
+
* transcript is content-sized, as before.
|
|
142
169
|
*/
|
|
143
|
-
export type ThreadFeedRowProps = ThreadFeedRowBase &
|
|
170
|
+
export type ThreadFeedRowProps = ThreadFeedRowBase &
|
|
171
|
+
RowHeightProps &
|
|
172
|
+
SlotStylesProps<'root' | 'header' | 'body'> &
|
|
173
|
+
BasaltProps
|
|
174
|
+
|
|
175
|
+
/** The row header's title: the `title` prop override, else the resolved outcome title, else a
|
|
176
|
+
* plain placeholder — this row never falls back to scanning the first user message the way
|
|
177
|
+
* `ThreadOutcomeCard`'s `promptOf` does, since an inline row's own expanded transcript already
|
|
178
|
+
* shows that prompt a scroll away. */
|
|
179
|
+
function rowTitle(thread: AgentThread<TranscriptPart>, titleOverride: string | undefined): string {
|
|
180
|
+
return titleOverride ?? thread.outcome?.title ?? 'Untitled thread'
|
|
181
|
+
}
|
|
144
182
|
|
|
145
|
-
/** The row header's
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
183
|
+
/** The row header's summary: the `summary` prop override, else the resolved outcome summary. */
|
|
184
|
+
function rowSummary(
|
|
185
|
+
thread: AgentThread<TranscriptPart>,
|
|
186
|
+
summaryOverride: string | undefined,
|
|
187
|
+
): string {
|
|
188
|
+
return summaryOverride ?? thread.outcome?.summary ?? ''
|
|
150
189
|
}
|
|
151
190
|
|
|
152
191
|
/**
|
|
@@ -162,6 +201,11 @@ export function ThreadFeedRow(props: ThreadFeedRowProps): JSX.Element {
|
|
|
162
201
|
thread,
|
|
163
202
|
expanded,
|
|
164
203
|
onToggle,
|
|
204
|
+
title,
|
|
205
|
+
summary: summaryOverride,
|
|
206
|
+
headerLeft,
|
|
207
|
+
headerRight,
|
|
208
|
+
messages,
|
|
165
209
|
liveParts,
|
|
166
210
|
liveStatus,
|
|
167
211
|
renderers,
|
|
@@ -171,16 +215,21 @@ export function ThreadFeedRow(props: ThreadFeedRowProps): JSX.Element {
|
|
|
171
215
|
onSend,
|
|
172
216
|
onStop,
|
|
173
217
|
composerProps,
|
|
218
|
+
classNames,
|
|
174
219
|
className,
|
|
175
220
|
style,
|
|
176
221
|
} = props
|
|
177
222
|
assertRequiredProps('ThreadFeedRow', { thread }, ['thread'])
|
|
178
223
|
|
|
179
224
|
// Resolved through the shared narrowing point rather than by destructuring `virtualize`/`height`
|
|
180
|
-
// apart — see `
|
|
181
|
-
|
|
225
|
+
// apart — see `resolveRowHeight`'s doc for why the two must be read together, and why it is a
|
|
226
|
+
// three-way (virtualized / bounded / content-sized) resolve rather than `resolveVirtualize`'s
|
|
227
|
+
// binary one (B3 adds the 'bounded' branch).
|
|
228
|
+
const rowHeight = resolveRowHeight(props)
|
|
182
229
|
const virtualizeProps: VirtualizeProps =
|
|
183
|
-
|
|
230
|
+
rowHeight.kind === 'virtualized'
|
|
231
|
+
? { virtualize: rowHeight.virtualize.options, height: rowHeight.virtualize.height }
|
|
232
|
+
: {}
|
|
184
233
|
|
|
185
234
|
// Lazy-mount + keep-mounted: flips true on the row's first expand and never resets. Everything
|
|
186
235
|
// below this line renders — once — the first time `expanded` becomes true, and stays in the tree
|
|
@@ -197,7 +246,9 @@ export function ThreadFeedRow(props: ThreadFeedRowProps): JSX.Element {
|
|
|
197
246
|
setHasOpened(true)
|
|
198
247
|
}
|
|
199
248
|
|
|
200
|
-
const
|
|
249
|
+
const resolvedTitle = rowTitle(thread, title)
|
|
250
|
+
const resolvedSummary = rowSummary(thread, summaryOverride)
|
|
251
|
+
const transcriptMessages = messages ?? thread.messages
|
|
201
252
|
|
|
202
253
|
// The composer half of `liveStatus`: `Composer` only shows its Stop action and gates the
|
|
203
254
|
// textarea when it is TOLD a run is streaming (`composer.tsx`'s `showStop`/`inputDisabled`) — it
|
|
@@ -205,18 +256,37 @@ export function ThreadFeedRow(props: ThreadFeedRowProps): JSX.Element {
|
|
|
205
256
|
// Stop never rendered and a second turn could still be typed into a live thread.
|
|
206
257
|
const streaming = liveStatus === 'streaming'
|
|
207
258
|
|
|
259
|
+
const transcript = (
|
|
260
|
+
<ThreadTranscript
|
|
261
|
+
messages={transcriptMessages}
|
|
262
|
+
{...(liveParts !== undefined ? { liveParts } : {})}
|
|
263
|
+
{...(liveStatus !== undefined ? { liveStatus } : {})}
|
|
264
|
+
{...(renderers !== undefined ? { renderers } : {})}
|
|
265
|
+
{...(fallbackRenderer !== undefined ? { fallbackRenderer } : {})}
|
|
266
|
+
{...(affordances !== undefined ? { affordances } : {})}
|
|
267
|
+
{...(groupConsecutive !== undefined ? { groupConsecutive } : {})}
|
|
268
|
+
{...virtualizeProps}
|
|
269
|
+
/>
|
|
270
|
+
)
|
|
271
|
+
|
|
208
272
|
return (
|
|
209
|
-
<Box
|
|
273
|
+
<Box
|
|
274
|
+
className={cx(classNames?.root, className)}
|
|
275
|
+
style={style ? { ...CARD_STYLE, ...style } : CARD_STYLE}
|
|
276
|
+
data-expanded={expanded}
|
|
277
|
+
>
|
|
210
278
|
<UnstyledButton
|
|
211
279
|
onClick={() => onToggle(thread.id)}
|
|
212
280
|
w="100%"
|
|
213
281
|
aria-expanded={expanded}
|
|
282
|
+
{...(classNames?.header !== undefined && { className: classNames.header })}
|
|
214
283
|
style={{
|
|
215
284
|
display: 'block',
|
|
216
285
|
padding: 'var(--mantine-spacing-xs) var(--mantine-spacing-sm)',
|
|
217
286
|
}}
|
|
218
287
|
>
|
|
219
288
|
<Group justify="space-between" gap="xs" wrap="nowrap" align="center">
|
|
289
|
+
{headerLeft}
|
|
220
290
|
<Stack gap={2} style={{ flex: 1, minWidth: 0 }}>
|
|
221
291
|
<Text
|
|
222
292
|
fw={550}
|
|
@@ -227,14 +297,15 @@ export function ThreadFeedRow(props: ThreadFeedRowProps): JSX.Element {
|
|
|
227
297
|
fontStretch: '88%',
|
|
228
298
|
}}
|
|
229
299
|
>
|
|
230
|
-
{
|
|
300
|
+
{resolvedTitle}
|
|
231
301
|
</Text>
|
|
232
|
-
{
|
|
302
|
+
{resolvedSummary.length > 0 && (
|
|
233
303
|
<Text size="xs" c="dimmed" lineClamp={1}>
|
|
234
|
-
{
|
|
304
|
+
{resolvedSummary}
|
|
235
305
|
</Text>
|
|
236
306
|
)}
|
|
237
307
|
</Stack>
|
|
308
|
+
{headerRight}
|
|
238
309
|
<Text
|
|
239
310
|
style={{
|
|
240
311
|
fontFamily: 'var(--basalt-font-mono)',
|
|
@@ -251,6 +322,7 @@ export function ThreadFeedRow(props: ThreadFeedRowProps): JSX.Element {
|
|
|
251
322
|
{hasOpened && (
|
|
252
323
|
<Box
|
|
253
324
|
data-testid="thread-feed-row-body"
|
|
325
|
+
{...(classNames?.body !== undefined && { className: classNames.body })}
|
|
254
326
|
style={{
|
|
255
327
|
display: expanded ? 'block' : 'none',
|
|
256
328
|
padding: 'var(--mantine-spacing-sm)',
|
|
@@ -258,16 +330,19 @@ export function ThreadFeedRow(props: ThreadFeedRowProps): JSX.Element {
|
|
|
258
330
|
}}
|
|
259
331
|
>
|
|
260
332
|
<Stack gap="sm">
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
333
|
+
{rowHeight.kind === 'bounded' ? (
|
|
334
|
+
<BasaltStickToBottom
|
|
335
|
+
style={{
|
|
336
|
+
height: rowHeight.height,
|
|
337
|
+
// theme-allow raw-scroll-container — BasaltStickToBottom owns this scroll node (see stick-to-bottom.tsx).
|
|
338
|
+
overflowY: 'auto',
|
|
339
|
+
}}
|
|
340
|
+
>
|
|
341
|
+
{transcript}
|
|
342
|
+
</BasaltStickToBottom>
|
|
343
|
+
) : (
|
|
344
|
+
transcript
|
|
345
|
+
)}
|
|
271
346
|
<Composer
|
|
272
347
|
onSubmit={onSend}
|
|
273
348
|
streaming={streaming}
|