@hachej/boring-agent 0.1.94 → 0.1.95

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.
@@ -140,12 +140,73 @@ var defaultChatSuggestions = [
140
140
  prompt: "Help me refactor a function \u2014 clean it up without changing behavior."
141
141
  }
142
142
  ];
143
+ function ChatSuggestionGrid({ suggestions, onSelect, className }) {
144
+ if (suggestions.length === 0) return null;
145
+ return /* @__PURE__ */ jsx2(
146
+ "div",
147
+ {
148
+ "data-boring-agent-part": "suggestion-grid",
149
+ style: {
150
+ ["--chat-empty-card-hover"]: "var(--accent-soft)",
151
+ ["--chat-empty-accent"]: "var(--accent)"
152
+ },
153
+ className: cn(
154
+ "grid w-full grid-cols-1 gap-px overflow-hidden rounded-xl bg-border/70 ring-1 ring-border/70 @[480px]:grid-cols-2",
155
+ className
156
+ ),
157
+ children: suggestions.map((suggestion) => {
158
+ const Icon = suggestion.icon;
159
+ return /* @__PURE__ */ jsxs(
160
+ Button,
161
+ {
162
+ type: "button",
163
+ variant: "ghost",
164
+ "data-boring-agent-part": "suggestion-card",
165
+ onClick: () => {
166
+ if (suggestion.onSelect) {
167
+ suggestion.onSelect();
168
+ return;
169
+ }
170
+ onSelect?.(suggestion);
171
+ },
172
+ className: "group h-auto justify-start gap-3 rounded-none bg-background px-4 py-3.5 text-left hover:bg-[color:var(--chat-empty-card-hover)] focus-visible:bg-[color:var(--chat-empty-card-hover)]",
173
+ children: [
174
+ Icon && /* @__PURE__ */ jsx2(
175
+ Icon,
176
+ {
177
+ className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground transition-colors group-hover:text-[color:var(--chat-empty-accent)]",
178
+ strokeWidth: 1.75
179
+ }
180
+ ),
181
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
182
+ /* @__PURE__ */ jsx2("span", { className: "text-[13px] font-medium text-foreground", children: suggestion.label }),
183
+ suggestion.hint && /* @__PURE__ */ jsx2("span", { className: "text-[12px] text-muted-foreground", children: suggestion.hint })
184
+ ] }),
185
+ /* @__PURE__ */ jsx2(
186
+ ArrowUpRight,
187
+ {
188
+ className: cn(
189
+ "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground opacity-0 transition-all duration-200 ease-[cubic-bezier(0.22,1,0.36,1)]",
190
+ "group-hover:translate-x-0.5 group-hover:-translate-y-0.5 group-hover:opacity-100 group-hover:text-[color:var(--chat-empty-accent)]"
191
+ ),
192
+ strokeWidth: 2
193
+ }
194
+ )
195
+ ]
196
+ },
197
+ suggestion.label
198
+ );
199
+ })
200
+ }
201
+ );
202
+ }
143
203
  function ChatEmptyState({
144
204
  eyebrow = "New session",
145
- title = "What are we building?",
205
+ title = "What should we work on?",
146
206
  description = "Ask a question, open a file from the workbench, or start from a template.",
147
207
  suggestions = defaultChatSuggestions,
148
208
  onSelect,
209
+ hero = false,
149
210
  footer,
150
211
  className
151
212
  }) {
@@ -164,65 +225,20 @@ function ChatEmptyState({
164
225
  // @container lets the hero scale to the pane it lives in, not the
165
226
  // viewport — split chat panes get the compact variant.
166
227
  "@container mx-auto flex w-full max-w-[640px] flex-col px-2 pt-12 pb-4",
228
+ hero && "items-center py-0 text-center",
167
229
  className
168
230
  ),
169
231
  children: [
170
- eyebrow && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-[10.5px] font-medium uppercase tracking-[0.16em] text-[color:var(--chat-empty-eyebrow-color)]", children: [
232
+ !hero && eyebrow && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-[10.5px] font-medium uppercase tracking-[0.16em] text-[color:var(--chat-empty-eyebrow-color)]", children: [
171
233
  /* @__PURE__ */ jsx2("span", { className: "inline-block h-px w-4 bg-[color:var(--chat-empty-accent)]", "aria-hidden": "true" }),
172
234
  eyebrow
173
235
  ] }),
174
- title && /* @__PURE__ */ jsx2("h3", { className: "mt-3 text-[24px] font-medium leading-[1.05] tracking-[-0.02em] text-[color:var(--chat-empty-title-color)] @[480px]:text-[34px]", children: title }),
175
- description && /* @__PURE__ */ jsx2("p", { className: "mt-3 hidden max-w-[440px] text-[14px] leading-relaxed text-[color:var(--chat-empty-description-color)] @[420px]:block", children: description }),
176
- suggestions.length > 0 && /* @__PURE__ */ jsx2(
177
- "div",
178
- {
179
- "data-boring-agent-part": "suggestion-grid",
180
- className: "mt-8 grid w-full grid-cols-1 gap-px overflow-hidden rounded-xl bg-border/70 ring-1 ring-border/70 @[480px]:grid-cols-2",
181
- children: suggestions.map((suggestion) => {
182
- const Icon = suggestion.icon;
183
- return /* @__PURE__ */ jsxs(
184
- Button,
185
- {
186
- type: "button",
187
- variant: "ghost",
188
- "data-boring-agent-part": "suggestion-card",
189
- onClick: () => {
190
- if (suggestion.onSelect) {
191
- suggestion.onSelect();
192
- return;
193
- }
194
- onSelect?.(suggestion);
195
- },
196
- className: "group h-auto justify-start gap-3 rounded-none bg-background px-4 py-3.5 text-left hover:bg-[color:var(--chat-empty-card-hover)] focus-visible:bg-[color:var(--chat-empty-card-hover)]",
197
- children: [
198
- Icon && /* @__PURE__ */ jsx2(
199
- Icon,
200
- {
201
- className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground transition-colors group-hover:text-[color:var(--chat-empty-accent)]",
202
- strokeWidth: 1.75
203
- }
204
- ),
205
- /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
206
- /* @__PURE__ */ jsx2("span", { className: "text-[13px] font-medium text-foreground", children: suggestion.label }),
207
- suggestion.hint && /* @__PURE__ */ jsx2("span", { className: "text-[12px] text-muted-foreground", children: suggestion.hint })
208
- ] }),
209
- /* @__PURE__ */ jsx2(
210
- ArrowUpRight,
211
- {
212
- className: cn(
213
- "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground opacity-0 transition-all duration-200 ease-[cubic-bezier(0.22,1,0.36,1)]",
214
- "group-hover:translate-x-0.5 group-hover:-translate-y-0.5 group-hover:opacity-100 group-hover:text-[color:var(--chat-empty-accent)]"
215
- ),
216
- strokeWidth: 2
217
- }
218
- )
219
- ]
220
- },
221
- suggestion.label
222
- );
223
- })
224
- }
225
- ),
236
+ title && /* @__PURE__ */ jsx2("h3", { className: cn(
237
+ "text-[24px] font-medium leading-[1.05] tracking-[-0.02em] text-[color:var(--chat-empty-title-color)] @[480px]:text-[34px]",
238
+ hero ? "m-0" : "mt-3"
239
+ ), children: title }),
240
+ !hero && description && /* @__PURE__ */ jsx2("p", { className: "mt-3 hidden max-w-[440px] text-[14px] leading-relaxed text-[color:var(--chat-empty-description-color)] @[420px]:block", children: description }),
241
+ /* @__PURE__ */ jsx2(ChatSuggestionGrid, { suggestions, onSelect, className: hero ? "mt-4" : "mt-8" }),
226
242
  footer
227
243
  ]
228
244
  }
@@ -7752,7 +7768,7 @@ function PiConversationSurface({
7752
7768
  return /* @__PURE__ */ jsxs21(
7753
7769
  Conversation,
7754
7770
  {
7755
- className: emptyHero ? "max-h-[45vh] flex-none" : "flex-1",
7771
+ className: emptyHero ? cn("flex-none", runtimeNotices.length > 0 ? "max-h-[45vh]" : "max-h-[20vh]") : "flex-1",
7756
7772
  "aria-label": "Agent conversation",
7757
7773
  "aria-live": "polite",
7758
7774
  onScrollToBottomReady,
@@ -7772,9 +7788,9 @@ function PiConversationSurface({
7772
7788
  eyebrow: emptyState?.eyebrow,
7773
7789
  title: emptyState?.title,
7774
7790
  description: emptyState?.description,
7775
- footer: emptyState?.footer,
7776
- suggestions,
7777
- className: emptyHero ? "items-center text-center [&>p]:mx-auto" : void 0,
7791
+ footer: emptyHero ? void 0 : emptyState?.footer,
7792
+ suggestions: emptyHero ? [] : suggestions,
7793
+ hero: emptyHero,
7778
7794
  onSelect: (suggestion) => {
7779
7795
  const text = suggestion.prompt ?? suggestion.label;
7780
7796
  if (!text.trim()) return;
@@ -8229,9 +8245,9 @@ function displayProviderLabel(provider) {
8229
8245
  import { Fragment as Fragment10, jsx as jsx30, jsxs as jsxs25 } from "react/jsx-runtime";
8230
8246
  var composerActionClass = cn(
8231
8247
  "inline-flex h-8 items-center justify-center gap-1.5 rounded-[var(--radius-md)] border-0 bg-transparent",
8232
- "text-muted-foreground shadow-none transition",
8248
+ "text-muted-foreground shadow-none transition-colors motion-reduce:transition-none",
8233
8249
  "hover:bg-muted/60 hover:text-foreground",
8234
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring/40",
8250
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-popover",
8235
8251
  "disabled:pointer-events-none disabled:opacity-50"
8236
8252
  );
8237
8253
  var THINKING_LEVEL_LABELS = {
@@ -8241,10 +8257,10 @@ var THINKING_LEVEL_LABELS = {
8241
8257
  high: "High"
8242
8258
  };
8243
8259
  var THINKING_LEVEL_STATUS_LABELS = {
8244
- off: "off",
8245
- low: "low",
8246
- medium: "medium",
8247
- high: "high"
8260
+ off: "Off",
8261
+ low: "Low",
8262
+ medium: "Medium",
8263
+ high: "High"
8248
8264
  };
8249
8265
  var THINKING_LEVEL_DETAILS = {
8250
8266
  off: "No extra reasoning",
@@ -8254,7 +8270,7 @@ var THINKING_LEVEL_DETAILS = {
8254
8270
  };
8255
8271
  var selectorTriggerClass = cn(
8256
8272
  composerActionClass,
8257
- "h-7 rounded-lg border border-border/60 bg-transparent px-2 text-[12px] font-medium text-muted-foreground",
8273
+ "h-8 rounded-lg border border-border/60 bg-transparent px-2 text-xs font-medium text-muted-foreground",
8258
8274
  "hover:border-border/80 hover:bg-muted/55 hover:text-foreground"
8259
8275
  );
8260
8276
  var selectorContentClass = cn(
@@ -8262,12 +8278,12 @@ var selectorContentClass = cn(
8262
8278
  "bg-[color:var(--popover)] p-1 text-[color:var(--popover-foreground)] shadow-xl"
8263
8279
  );
8264
8280
  var composerPickerMenuClass = cn(
8265
- "mb-1 w-full overflow-hidden rounded-lg border border-border/60",
8266
- "bg-[color:var(--popover)] text-[color:var(--popover-foreground)] shadow-lg"
8281
+ "w-full overflow-hidden rounded-xl border border-border",
8282
+ "bg-[color:var(--popover)] text-[color:var(--popover-foreground)] shadow-xl"
8267
8283
  );
8268
8284
  function selectorItemClass(selected) {
8269
8285
  return cn(
8270
- "flex items-center gap-2 rounded-md px-2 py-1.5 text-[13px]",
8286
+ "flex min-h-10 items-center gap-2 rounded-md px-2.5 py-2 text-sm text-muted-foreground",
8271
8287
  "data-[selected=true]:bg-[color:oklch(from_var(--accent)_l_c_h/0.15)] data-[selected=true]:text-foreground",
8272
8288
  selected && "bg-foreground/[0.06] text-foreground"
8273
8289
  );
@@ -8322,7 +8338,8 @@ function ThinkingLevelGlyph({ level }) {
8322
8338
  function modelTriggerLabel(value, options, emptyLabel = "Default model") {
8323
8339
  const current = value ? options.find((m) => m.provider === value.provider && m.id === value.id) : void 0;
8324
8340
  const rawTriggerLabel = current?.label ?? value?.id;
8325
- return value ? rawTriggerLabel && current?.label && current.label !== value.id && /[A-Z]/.test(current.label) ? current.label : displayModelLabel(rawTriggerLabel ?? value.id) : emptyLabel;
8341
+ const label = value ? rawTriggerLabel && current?.label && current.label !== value.id && /[A-Z]/.test(current.label) ? current.label : displayModelLabel(rawTriggerLabel ?? value.id) : emptyLabel;
8342
+ return value ? label.replace(/\s+\([^)]*\)\s*$/, "") : label;
8326
8343
  }
8327
8344
  function modelMenuOptions(_value, options) {
8328
8345
  return options.filter((m) => m.available);
@@ -8361,15 +8378,19 @@ var ModelSelectTrigger = forwardRef(function ModelSelectTrigger2({
8361
8378
  title: trigger === "slash" ? `Open model picker. Current model: ${triggerDisplay}` : void 0,
8362
8379
  onClick,
8363
8380
  className: cn(
8364
- trigger === "slash" ? "max-w-[min(52vw,260px)] cursor-pointer overflow-hidden text-ellipsis whitespace-nowrap rounded-[var(--radius-md)] px-1.5 py-0.5 transition-colors hover:bg-foreground/[0.045] hover:text-foreground/80 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-foreground/20 disabled:pointer-events-none disabled:opacity-50" : selectorTriggerClass,
8381
+ trigger === "slash" ? "h-8 max-w-[min(68vw,420px)] cursor-pointer overflow-hidden text-ellipsis whitespace-nowrap rounded-[var(--radius-md)] px-2 text-xs transition-colors hover:bg-muted/60 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-popover disabled:pointer-events-none disabled:opacity-50 motion-reduce:transition-none" : selectorTriggerClass,
8365
8382
  trigger === "slash" ? "w-auto" : "w-auto max-w-[min(52vw,260px)] gap-1",
8366
8383
  open && (trigger === "slash" ? "bg-muted/45" : "border-border/80 bg-muted/55 text-foreground"),
8367
8384
  className
8368
8385
  ),
8369
8386
  ...props,
8370
8387
  children: trigger === "slash" ? /* @__PURE__ */ jsxs25(Fragment10, { children: [
8371
- /* @__PURE__ */ jsx30("span", { className: "text-muted-foreground", children: "/model: " }),
8372
- /* @__PURE__ */ jsx30("span", { className: "text-foreground", children: triggerDisplay })
8388
+ /* @__PURE__ */ jsx30("span", { className: "text-muted-foreground", children: "Model \xB7 " }),
8389
+ /* @__PURE__ */ jsx30("span", { className: "min-w-0 truncate text-foreground", children: triggerLabel }),
8390
+ value ? /* @__PURE__ */ jsxs25("span", { className: "shrink-0 text-muted-foreground", children: [
8391
+ " \xB7 ",
8392
+ displayProviderLabel(value.provider)
8393
+ ] }) : null
8373
8394
  ] }) : /* @__PURE__ */ jsxs25(Fragment10, { children: [
8374
8395
  /* @__PURE__ */ jsx30("span", { className: "min-w-0 truncate", children: triggerDisplay }),
8375
8396
  /* @__PURE__ */ jsx30(ChevronDownIcon5, { className: "h-3 w-3 shrink-0 text-muted-foreground/50", "aria-hidden": "true" })
@@ -8435,11 +8456,11 @@ function ModelPickerMenu({
8435
8456
  {
8436
8457
  placeholder: "Search models\u2026",
8437
8458
  autoFocus: true,
8438
- className: "h-8 w-full border-0 bg-transparent text-[13px] outline-none focus:ring-0"
8459
+ className: "h-8 w-full border-0 bg-transparent text-sm outline-none focus:ring-0"
8439
8460
  }
8440
8461
  ) }),
8441
8462
  /* @__PURE__ */ jsxs25(CommandList, { className: "max-h-[300px] p-0.5", children: [
8442
- /* @__PURE__ */ jsx30(CommandEmpty, { className: "py-4 text-center text-[13px] text-muted-foreground", children: "No models found" }),
8463
+ /* @__PURE__ */ jsx30(CommandEmpty, { className: "py-4 text-center text-sm text-muted-foreground", children: "No models found" }),
8443
8464
  !hideDefaultOption ? /* @__PURE__ */ jsx30(CommandGroup, { children: /* @__PURE__ */ jsxs25(
8444
8465
  CommandItem,
8445
8466
  {
@@ -8461,7 +8482,7 @@ function ModelPickerMenu({
8461
8482
  }
8462
8483
  ),
8463
8484
  /* @__PURE__ */ jsx30("span", { className: "truncate", children: "Default model" }),
8464
- /* @__PURE__ */ jsx30("span", { className: "ml-auto shrink-0 text-[10px] text-muted-foreground/60", children: "auto" })
8485
+ /* @__PURE__ */ jsx30("span", { className: "ml-auto shrink-0 text-xs text-muted-foreground", children: "Auto" })
8465
8486
  ]
8466
8487
  }
8467
8488
  ) }) : null,
@@ -8469,7 +8490,7 @@ function ModelPickerMenu({
8469
8490
  CommandGroup,
8470
8491
  {
8471
8492
  heading: displayProviderLabel(provider),
8472
- className: "[&_[cmdk-group-heading]]:px-2.5 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-[10px] [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-[0.08em] [&_[cmdk-group-heading]]:text-muted-foreground/60",
8493
+ className: "[&_[cmdk-group-heading]]:px-2.5 [&_[cmdk-group-heading]]:py-2 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-[0.08em] [&_[cmdk-group-heading]]:text-muted-foreground",
8473
8494
  children: list.map((m) => {
8474
8495
  const key = encodeModelKey(m);
8475
8496
  const label = m.label || displayModelLabel(m.id);
@@ -8495,7 +8516,7 @@ function ModelPickerMenu({
8495
8516
  }
8496
8517
  ),
8497
8518
  /* @__PURE__ */ jsx30("span", { className: "min-w-0 flex-1 truncate whitespace-nowrap", children: label }),
8498
- /* @__PURE__ */ jsx30("span", { className: "ml-auto max-w-[45%] shrink-0 truncate whitespace-nowrap text-right text-[10px] text-muted-foreground/60", children: m.id })
8519
+ /* @__PURE__ */ jsx30("span", { className: "ml-auto max-w-[45%] shrink-0 truncate whitespace-nowrap text-right text-xs text-muted-foreground", children: m.id })
8499
8520
  ]
8500
8521
  },
8501
8522
  key
@@ -8646,7 +8667,7 @@ var ThinkingSelectTrigger = forwardRef(function ThinkingSelectTrigger2({
8646
8667
  "data-boring-state": disabled ? "disabled" : void 0,
8647
8668
  disabled,
8648
8669
  className: cn(
8649
- trigger === "slash" ? "cursor-pointer rounded-[var(--radius-md)] px-1.5 py-0.5 transition-colors hover:bg-foreground/[0.045] hover:text-foreground/80 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-foreground/20 disabled:pointer-events-none disabled:opacity-50" : selectorTriggerClass,
8670
+ trigger === "slash" ? "h-8 cursor-pointer rounded-[var(--radius-md)] px-2 text-xs transition-colors hover:bg-muted/60 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-popover disabled:pointer-events-none disabled:opacity-50 motion-reduce:transition-none" : selectorTriggerClass,
8650
8671
  trigger === "button" && "gap-1.5",
8651
8672
  trigger === "button" && value !== "off" && !open && "border-[color:oklch(from_var(--accent)_l_c_h/0.35)] bg-[color:oklch(from_var(--accent)_l_c_h/0.08)] text-foreground",
8652
8673
  open && (trigger === "slash" ? "bg-muted/45" : "border-border/80 bg-muted/55 text-foreground"),
@@ -8660,7 +8681,7 @@ var ThinkingSelectTrigger = forwardRef(function ThinkingSelectTrigger2({
8660
8681
  children: [
8661
8682
  trigger === "button" ? /* @__PURE__ */ jsx30(ThinkingLevelGlyph, { level: value }) : null,
8662
8683
  trigger === "slash" ? /* @__PURE__ */ jsxs25(Fragment10, { children: [
8663
- /* @__PURE__ */ jsx30("span", { className: "text-muted-foreground", children: "/thinking: " }),
8684
+ /* @__PURE__ */ jsx30("span", { className: "text-muted-foreground", children: "Thinking \xB7 " }),
8664
8685
  /* @__PURE__ */ jsx30("span", { className: "text-foreground", children: THINKING_LEVEL_STATUS_LABELS[value] })
8665
8686
  ] }) : /* @__PURE__ */ jsxs25(Fragment10, { children: [
8666
8687
  /* @__PURE__ */ jsx30("span", { children: THINKING_LEVEL_LABELS[value] }),
@@ -8735,7 +8756,7 @@ function ThinkingPickerMenu({
8735
8756
  ),
8736
8757
  /* @__PURE__ */ jsx30(ThinkingLevelGlyph, { level }),
8737
8758
  /* @__PURE__ */ jsx30("span", { className: "font-medium", children: THINKING_LEVEL_LABELS[level] }),
8738
- /* @__PURE__ */ jsx30("span", { className: "ml-auto text-[11px] text-muted-foreground/65", children: THINKING_LEVEL_DETAILS[level] })
8759
+ /* @__PURE__ */ jsx30("span", { className: "ml-auto text-xs text-muted-foreground", children: THINKING_LEVEL_DETAILS[level] })
8739
8760
  ]
8740
8761
  },
8741
8762
  level
@@ -9482,10 +9503,10 @@ function AttachmentButton({ disabled, className }) {
9482
9503
  onClick: () => {
9483
9504
  if (!disabled) attachments.openFileDialog();
9484
9505
  },
9485
- className: cn(composerActionClass, "w-8", className),
9506
+ className: cn(composerActionClass, "!h-10 !w-10", className),
9486
9507
  "aria-label": "Attach files",
9487
9508
  title: disabled ? "Attachments are available when the composer is ready." : "Attach files",
9488
- children: /* @__PURE__ */ jsx34(PaperclipIcon2, { className: "h-3.5 w-3.5", strokeWidth: 1.75 })
9509
+ children: /* @__PURE__ */ jsx34(PaperclipIcon2, { className: "h-4 w-4", strokeWidth: 1.75 })
9489
9510
  }
9490
9511
  );
9491
9512
  }
@@ -9550,6 +9571,7 @@ function hasSoftWrappedLine(node, style) {
9550
9571
  }
9551
9572
  function PiChatComposerSurface({
9552
9573
  chrome,
9574
+ pickerPlacement = "above",
9553
9575
  isStreaming,
9554
9576
  status,
9555
9577
  disabled,
@@ -9639,7 +9661,10 @@ function PiChatComposerSurface({
9639
9661
  useLayoutEffect2(() => {
9640
9662
  resizeTextarea(textareaRef.current);
9641
9663
  }, [draft, resizeTextarea, textareaRef]);
9642
- return /* @__PURE__ */ jsxs30("div", { className: cn("relative z-20", chrome ? "px-4 pb-4 pt-2 sm:px-6 sm:pb-5" : "px-3 pb-2 pt-1"), children: [
9664
+ return /* @__PURE__ */ jsxs30("div", { className: cn(
9665
+ "relative z-20",
9666
+ chrome ? "pb-[calc(1rem+env(safe-area-inset-bottom))] pl-[calc(1rem+env(safe-area-inset-left))] pr-[calc(1rem+env(safe-area-inset-right))] pt-2 sm:pb-[calc(1.25rem+env(safe-area-inset-bottom))] sm:pl-[calc(1.5rem+env(safe-area-inset-left))] sm:pr-[calc(1.5rem+env(safe-area-inset-right))]" : "pb-[calc(0.5rem+env(safe-area-inset-bottom))] pl-[calc(0.75rem+env(safe-area-inset-left))] pr-[calc(0.75rem+env(safe-area-inset-right))] pt-1"
9667
+ ), children: [
9643
9668
  /* @__PURE__ */ jsx35(
9644
9669
  "div",
9645
9670
  {
@@ -9707,219 +9732,223 @@ function PiChatComposerSurface({
9707
9732
  children: attachmentNotice
9708
9733
  }
9709
9734
  ) : null,
9710
- /* @__PURE__ */ jsxs30("div", { className: cn("mx-auto w-full", chrome ? "max-w-3xl" : "max-w-[680px]"), children: [
9711
- mentionState ? /* @__PURE__ */ jsx35(
9712
- MentionPicker,
9713
- {
9714
- mention: mentionState,
9715
- apiBaseUrl,
9716
- fetch: fetch2,
9717
- requestHeaders,
9718
- storageScope,
9719
- onSelect: onSelectMention,
9720
- onDismiss: onDismissMention
9721
- }
9722
- ) : null,
9723
- slashQuery !== null ? /* @__PURE__ */ jsx35(
9724
- SlashCommandPicker,
9735
+ /* @__PURE__ */ jsxs30("div", { className: cn("@container group/composer relative mx-auto w-full", chrome ? "max-w-3xl" : "max-w-[680px]"), children: [
9736
+ /* @__PURE__ */ jsxs30("div", { className: cn(
9737
+ "absolute inset-x-0 z-30",
9738
+ pickerPlacement === "above-compact" ? "bottom-[calc(100%+4px)] [&_[cmdk-list]]:!max-h-[200px]" : "bottom-[calc(100%+4px)]"
9739
+ ), children: [
9740
+ mentionState ? /* @__PURE__ */ jsx35("div", { className: "mr-px ml-[43px]", children: /* @__PURE__ */ jsx35(
9741
+ MentionPicker,
9742
+ {
9743
+ mention: mentionState,
9744
+ apiBaseUrl,
9745
+ fetch: fetch2,
9746
+ requestHeaders,
9747
+ storageScope,
9748
+ onSelect: onSelectMention,
9749
+ onDismiss: onDismissMention
9750
+ }
9751
+ ) }) : null,
9752
+ slashQuery !== null ? /* @__PURE__ */ jsx35("div", { className: "mr-px ml-[43px]", children: /* @__PURE__ */ jsx35(
9753
+ SlashCommandPicker,
9754
+ {
9755
+ query: slashQuery,
9756
+ commands,
9757
+ onSelect: onSelectSlashCommand,
9758
+ onDismiss: onDismissSlash
9759
+ }
9760
+ ) }) : null,
9761
+ mentionState === null && slashQuery === null && modelPickerOpen ? /* @__PURE__ */ jsx35("div", { className: "mr-px mb-1 ml-[43px]", children: /* @__PURE__ */ jsx35(
9762
+ ModelPickerMenu,
9763
+ {
9764
+ value: selectedModel,
9765
+ onChange: onModelChange,
9766
+ options: modelOptions,
9767
+ disabled: isStreaming || modelControlled,
9768
+ hideDefaultOption: hideDefaultModelOption,
9769
+ onClose: () => onSetModelPickerOpen(false)
9770
+ }
9771
+ ) }) : null,
9772
+ mentionState === null && slashQuery === null && thinkingPickerOpen ? /* @__PURE__ */ jsx35("div", { className: "mr-px mb-1 ml-[43px]", children: /* @__PURE__ */ jsx35(
9773
+ ThinkingPickerMenu,
9774
+ {
9775
+ value: selectedThinking,
9776
+ onChange: onThinkingChange,
9777
+ disabled: isStreaming || thinkingControlled,
9778
+ onClose: () => onSetThinkingPickerOpen(false)
9779
+ }
9780
+ ) }) : null
9781
+ ] }),
9782
+ composerContributions.map(({ id, Top }) => Top ? /* @__PURE__ */ jsx35(
9783
+ "div",
9725
9784
  {
9726
- query: slashQuery,
9727
- commands,
9728
- onSelect: onSelectSlashCommand,
9729
- onDismiss: onDismissSlash
9730
- }
9731
- ) : null,
9732
- mentionState === null && slashQuery === null && modelPickerOpen ? /* @__PURE__ */ jsx35(
9733
- ModelPickerMenu,
9785
+ "data-boring-agent-part": "composer-contribution-top",
9786
+ "data-boring-agent-contribution-id": id,
9787
+ className: cn("mx-auto mb-2 w-full empty:hidden", chrome ? "max-w-3xl" : "max-w-[680px]"),
9788
+ children: /* @__PURE__ */ jsx35(Top, {})
9789
+ },
9790
+ id
9791
+ ) : null),
9792
+ /* @__PURE__ */ jsx35(
9793
+ "div",
9734
9794
  {
9735
- value: selectedModel,
9736
- onChange: onModelChange,
9737
- options: modelOptions,
9738
- disabled: isStreaming || modelControlled,
9739
- hideDefaultOption: hideDefaultModelOption,
9740
- onClose: () => onSetModelPickerOpen(false)
9795
+ "data-boring-agent-part": "composer-rail",
9796
+ "data-composer-multiline": "false",
9797
+ style: { "--composer-input-group-height": `${COMPOSER_INPUT_GROUP_MIN_HEIGHT}px` },
9798
+ className: cn(
9799
+ "relative mx-auto w-full overflow-visible rounded-xl",
9800
+ chrome ? "max-w-3xl bg-transparent shadow-[0_1px_2px_-1px_oklch(0_0_0/0.06),0_6px_18px_-12px_oklch(0_0_0/0.12),inset_0_0_0_1px_oklch(from_var(--border)_l_c_h/0.7)] focus-within:shadow-[0_1px_3px_-1px_oklch(0_0_0/0.08),0_10px_28px_-14px_oklch(0_0_0/0.16),inset_0_0_0_1px_oklch(from_var(--accent)_l_c_h/0.45)]" : "max-w-[680px] bg-transparent shadow-[inset_0_0_0_1px_oklch(from_var(--border)_l_c_h/0.7)] focus-within:shadow-[inset_0_0_0_1px_oklch(from_var(--accent)_l_c_h/0.45)]",
9801
+ "transition-shadow duration-200 ease-[cubic-bezier(0.22,1,0.36,1)]",
9802
+ "[&_[data-slot=input-group]]:!h-auto [&_[data-slot=input-group]]:!min-h-[var(--composer-input-group-height)]",
9803
+ "[&_[data-slot=input-group]]:!flex-col [&_[data-slot=input-group]]:!items-stretch [&_[data-slot=input-group]]:!overflow-hidden",
9804
+ "[&_[data-slot=input-group]]:!border-0 [&_[data-slot=input-group]]:!rounded-xl",
9805
+ "[&_[data-slot=input-group]]:!bg-transparent [&_[data-slot=input-group]]:!shadow-none",
9806
+ "[&_[data-slot=input-group]]:dark:!bg-transparent [&_[data-slot=input-group]]:!ring-0",
9807
+ "[&_[data-slot=input-group]]:has-[:focus]:!ring-0",
9808
+ "[&[data-composer-multiline=true]_[data-boring-agent-part=composer-submit-addon]]:self-end",
9809
+ "[&[data-composer-multiline=true]_[data-boring-agent-part=composer-submit-addon]]:mb-2"
9810
+ ),
9811
+ children: /* @__PURE__ */ jsxs30(
9812
+ PromptInput,
9813
+ {
9814
+ "data-boring-state": status,
9815
+ onSubmit: (message) => onSubmitMessage({ text: message.text, files: message.files }),
9816
+ onUploadFile: uploadAttachment,
9817
+ multiple: true,
9818
+ maxFiles: disabled || isStreaming ? 0 : MAX_PROMPT_ATTACHMENTS,
9819
+ maxFileSize: MAX_PROMPT_ATTACHMENT_BYTES,
9820
+ onError: (err) => {
9821
+ if (err.code === "max_files") onAttachmentNotice(`Up to ${MAX_PROMPT_ATTACHMENTS} attachments per message.`);
9822
+ else if (err.code === "max_file_size") onAttachmentNotice("Files must be under 4 MB each.");
9823
+ else if (err.code === "accept") onAttachmentNotice("That file type isn't supported here.");
9824
+ else onAttachmentNotice(err.message || "Attachment rejected.");
9825
+ },
9826
+ children: [
9827
+ /* @__PURE__ */ jsx35(AttachmentsList, {}),
9828
+ /* @__PURE__ */ jsxs30(
9829
+ "div",
9830
+ {
9831
+ "data-boring-agent-part": "composer-input-row",
9832
+ className: "flex min-h-[var(--composer-input-group-height)] w-full items-center",
9833
+ children: [
9834
+ /* @__PURE__ */ jsx35("div", { className: "flex h-14 shrink-0 items-center pl-2", children: /* @__PURE__ */ jsx35(AttachmentButton, { disabled: disabled || isStreaming }) }),
9835
+ /* @__PURE__ */ jsx35(
9836
+ PromptInputTextarea,
9837
+ {
9838
+ value: draft,
9839
+ placeholder: composerBlocked ? workspaceWarmupBlocked ? composerBlockerLabel : "" : composerPlaceholder ?? "Ask anything\u2026",
9840
+ disabled,
9841
+ readOnly: composerBlocked,
9842
+ "aria-label": "Agent prompt",
9843
+ ref: (node) => {
9844
+ textareaRef.current = node;
9845
+ resizeTextarea(node);
9846
+ },
9847
+ onChange: onTextareaChange,
9848
+ onKeyDown: onTextareaKeyDown,
9849
+ style: { fieldSizing: "fixed" },
9850
+ className: cn(
9851
+ "min-w-0 flex-1 !min-h-10 !max-h-40 resize-none overflow-hidden border-0 bg-transparent shadow-none",
9852
+ "[field-sizing:fixed]",
9853
+ "px-2 py-2 text-sm leading-6 text-foreground",
9854
+ "placeholder:text-muted-foreground/60",
9855
+ "focus-visible:ring-0 focus-visible:ring-offset-0"
9856
+ )
9857
+ }
9858
+ ),
9859
+ /* @__PURE__ */ jsx35(
9860
+ PromptInputFooter,
9861
+ {
9862
+ align: "inline-end",
9863
+ "data-boring-agent-part": "composer-submit-addon",
9864
+ className: "!order-none !w-auto shrink-0 self-center justify-between border-0 bg-transparent !px-2 !py-0",
9865
+ children: /* @__PURE__ */ jsxs30("div", { className: "ml-auto flex items-center gap-1.5", children: [
9866
+ composerContributions.map(({ id, Action }) => Action ? /* @__PURE__ */ jsx35(
9867
+ "span",
9868
+ {
9869
+ "data-boring-agent-part": "composer-contribution-action",
9870
+ "data-boring-agent-contribution-id": id,
9871
+ className: "contents",
9872
+ children: /* @__PURE__ */ jsx35(Action, { updateDraft })
9873
+ },
9874
+ id
9875
+ ) : null),
9876
+ /* @__PURE__ */ jsx35(
9877
+ PromptInputSubmit,
9878
+ {
9879
+ "data-boring-agent-part": "composer-submit",
9880
+ status: submitStatus,
9881
+ onStop,
9882
+ disabled: submitDisabled,
9883
+ className: cn(
9884
+ "h-8 w-8 shrink-0 rounded-full",
9885
+ "bg-foreground text-background",
9886
+ "transition-all duration-150 ease-[cubic-bezier(0.22,1,0.36,1)]",
9887
+ "hover:bg-foreground/90 hover:shadow-[0_0_0_3px_oklch(from_var(--foreground)_l_c_h/0.12)] hover:scale-[1.04]",
9888
+ "active:scale-[0.93] active:brightness-95",
9889
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/20",
9890
+ "disabled:pointer-events-none disabled:opacity-40",
9891
+ "[&>svg]:size-3.5"
9892
+ )
9893
+ }
9894
+ )
9895
+ ] })
9896
+ }
9897
+ )
9898
+ ]
9899
+ }
9900
+ )
9901
+ ]
9902
+ }
9903
+ )
9741
9904
  }
9742
- ) : null,
9743
- mentionState === null && slashQuery === null && thinkingPickerOpen ? /* @__PURE__ */ jsx35(
9744
- ThinkingPickerMenu,
9905
+ ),
9906
+ hideComposerSettings ? null : /* @__PURE__ */ jsx35(
9907
+ "div",
9745
9908
  {
9746
- value: selectedThinking,
9747
- onChange: onThinkingChange,
9748
- disabled: isStreaming || thinkingControlled,
9749
- onClose: () => onSetThinkingPickerOpen(false)
9750
- }
9751
- ) : null
9752
- ] }),
9753
- composerContributions.map(({ id, Top }) => Top ? /* @__PURE__ */ jsx35(
9754
- "div",
9755
- {
9756
- "data-boring-agent-part": "composer-contribution-top",
9757
- "data-boring-agent-contribution-id": id,
9758
- className: cn("mx-auto mb-2 w-full empty:hidden", chrome ? "max-w-3xl" : "max-w-[680px]"),
9759
- children: /* @__PURE__ */ jsx35(Top, {})
9760
- },
9761
- id
9762
- ) : null),
9763
- /* @__PURE__ */ jsx35(
9764
- "div",
9765
- {
9766
- "data-boring-agent-part": "composer-rail",
9767
- "data-composer-multiline": "false",
9768
- style: { "--composer-input-group-height": `${COMPOSER_INPUT_GROUP_MIN_HEIGHT}px` },
9769
- className: cn(
9770
- "relative mx-auto w-full overflow-visible rounded-[28px]",
9771
- chrome ? "max-w-3xl bg-transparent shadow-[0_1px_2px_-1px_oklch(0_0_0/0.06),0_6px_18px_-12px_oklch(0_0_0/0.12),inset_0_0_0_1px_oklch(from_var(--border)_l_c_h/0.7)] focus-within:shadow-[0_1px_3px_-1px_oklch(0_0_0/0.08),0_10px_28px_-14px_oklch(0_0_0/0.16),inset_0_0_0_1px_oklch(from_var(--accent)_l_c_h/0.45)]" : "max-w-[680px] bg-transparent shadow-[inset_0_0_0_1px_oklch(from_var(--border)_l_c_h/0.7)] focus-within:shadow-[inset_0_0_0_1px_oklch(from_var(--accent)_l_c_h/0.45)]",
9772
- "transition-shadow duration-200 ease-[cubic-bezier(0.22,1,0.36,1)]",
9773
- "[&_[data-slot=input-group]]:!h-auto [&_[data-slot=input-group]]:!min-h-[var(--composer-input-group-height)]",
9774
- "[&_[data-slot=input-group]]:!flex-col [&_[data-slot=input-group]]:!items-stretch [&_[data-slot=input-group]]:!overflow-hidden",
9775
- "[&_[data-slot=input-group]]:!border-0 [&_[data-slot=input-group]]:!rounded-[28px]",
9776
- "[&_[data-slot=input-group]]:!bg-transparent [&_[data-slot=input-group]]:!shadow-none",
9777
- "[&_[data-slot=input-group]]:dark:!bg-transparent [&_[data-slot=input-group]]:!ring-0",
9778
- "[&_[data-slot=input-group]]:has-[:focus]:!ring-0",
9779
- "[&[data-composer-multiline=true]_[data-boring-agent-part=composer-submit-addon]]:self-end",
9780
- "[&[data-composer-multiline=true]_[data-boring-agent-part=composer-submit-addon]]:mb-2"
9781
- ),
9782
- children: /* @__PURE__ */ jsxs30(
9783
- PromptInput,
9784
- {
9785
- "data-boring-state": status,
9786
- onSubmit: (message) => onSubmitMessage({ text: message.text, files: message.files }),
9787
- onUploadFile: uploadAttachment,
9788
- multiple: true,
9789
- maxFiles: disabled || isStreaming ? 0 : MAX_PROMPT_ATTACHMENTS,
9790
- maxFileSize: MAX_PROMPT_ATTACHMENT_BYTES,
9791
- onError: (err) => {
9792
- if (err.code === "max_files") onAttachmentNotice(`Up to ${MAX_PROMPT_ATTACHMENTS} attachments per message.`);
9793
- else if (err.code === "max_file_size") onAttachmentNotice("Files must be under 4 MB each.");
9794
- else if (err.code === "accept") onAttachmentNotice("That file type isn't supported here.");
9795
- else onAttachmentNotice(err.message || "Attachment rejected.");
9796
- },
9797
- children: [
9798
- /* @__PURE__ */ jsx35(AttachmentsList, {}),
9799
- /* @__PURE__ */ jsxs30(
9800
- "div",
9801
- {
9802
- "data-boring-agent-part": "composer-input-row",
9803
- className: "flex min-h-[var(--composer-input-group-height)] w-full items-center",
9804
- children: [
9805
- /* @__PURE__ */ jsx35("div", { className: "flex h-14 shrink-0 items-center pl-2", children: /* @__PURE__ */ jsx35(AttachmentButton, { disabled: disabled || isStreaming }) }),
9806
- /* @__PURE__ */ jsx35(
9807
- PromptInputTextarea,
9808
- {
9809
- value: draft,
9810
- placeholder: composerBlocked ? workspaceWarmupBlocked ? composerBlockerLabel : "" : composerPlaceholder ?? "Ask anything\u2026",
9811
- disabled,
9812
- readOnly: composerBlocked,
9813
- "aria-label": "Agent prompt",
9814
- ref: (node) => {
9815
- textareaRef.current = node;
9816
- resizeTextarea(node);
9817
- },
9818
- onChange: onTextareaChange,
9819
- onKeyDown: onTextareaKeyDown,
9820
- style: { fieldSizing: "fixed" },
9821
- className: cn(
9822
- "min-w-0 flex-1 !min-h-10 !max-h-40 resize-none overflow-hidden border-0 bg-transparent shadow-none",
9823
- "[field-sizing:fixed]",
9824
- "px-2 py-2 text-[13px] leading-6",
9825
- "placeholder:text-muted-foreground/45",
9826
- "focus-visible:ring-0 focus-visible:ring-offset-0"
9827
- )
9828
- }
9829
- ),
9830
- /* @__PURE__ */ jsx35(
9831
- PromptInputFooter,
9832
- {
9833
- align: "inline-end",
9834
- "data-boring-agent-part": "composer-submit-addon",
9835
- className: "!order-none !w-auto shrink-0 self-center justify-between border-0 bg-transparent !px-2 !py-0",
9836
- children: /* @__PURE__ */ jsxs30("div", { className: "ml-auto flex items-center gap-1.5", children: [
9837
- composerContributions.map(({ id, Action }) => Action ? /* @__PURE__ */ jsx35(
9838
- "span",
9839
- {
9840
- "data-boring-agent-part": "composer-contribution-action",
9841
- "data-boring-agent-contribution-id": id,
9842
- className: "contents",
9843
- children: /* @__PURE__ */ jsx35(Action, { updateDraft })
9844
- },
9845
- id
9846
- ) : null),
9847
- /* @__PURE__ */ jsx35(
9848
- PromptInputSubmit,
9849
- {
9850
- "data-boring-agent-part": "composer-submit",
9851
- status: submitStatus,
9852
- onStop,
9853
- disabled: submitDisabled,
9854
- className: cn(
9855
- "h-8 w-8 shrink-0 rounded-full",
9856
- "bg-foreground",
9857
- "text-background",
9858
- "transition-all duration-150 ease-[cubic-bezier(0.22,1,0.36,1)]",
9859
- "hover:bg-foreground/90 hover:shadow-[0_0_0_3px_oklch(from_var(--foreground)_l_c_h/0.12)] hover:scale-[1.04]",
9860
- "active:scale-[0.93] active:brightness-95",
9861
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/20",
9862
- "disabled:pointer-events-none disabled:opacity-40",
9863
- "[&>svg]:size-3.5"
9864
- )
9865
- }
9866
- )
9867
- ] })
9868
- }
9869
- )
9870
- ]
9871
- }
9872
- )
9873
- ]
9874
- }
9875
- )
9876
- }
9877
- ),
9878
- hideComposerSettings ? null : /* @__PURE__ */ jsxs30(
9879
- "div",
9880
- {
9881
- "data-boring-agent-part": "composer-settings-row",
9882
- className: cn(
9883
- "mx-auto mt-1.5 flex w-full items-center justify-center gap-1.5 text-[10.5px] text-muted-foreground/45",
9884
- chrome ? "max-w-3xl" : "max-w-[680px]"
9885
- ),
9886
- children: [
9887
- /* @__PURE__ */ jsx35(
9888
- ModelSelectTrigger,
9889
- {
9890
- value: selectedModel,
9891
- options: modelOptions,
9892
- disabled: isStreaming || modelControlled,
9893
- trigger: "slash",
9894
- open: modelPickerOpen,
9895
- onClick: () => {
9896
- if (modelPickerOpen) {
9897
- onSetModelPickerOpen(false);
9898
- return;
9909
+ "data-boring-agent-part": "composer-settings-row",
9910
+ className: cn(
9911
+ "mx-auto mt-2 grid min-h-8 w-full grid-cols-[minmax(0,1fr)_auto] items-center text-xs text-muted-foreground",
9912
+ chrome ? "max-w-3xl" : "max-w-[680px]"
9913
+ ),
9914
+ children: /* @__PURE__ */ jsxs30("div", { className: "flex min-w-0 items-center justify-center gap-1", children: [
9915
+ /* @__PURE__ */ jsx35(
9916
+ ModelSelectTrigger,
9917
+ {
9918
+ value: selectedModel,
9919
+ options: modelOptions,
9920
+ disabled: isStreaming || modelControlled,
9921
+ trigger: "slash",
9922
+ open: modelPickerOpen,
9923
+ onClick: () => {
9924
+ if (modelPickerOpen) {
9925
+ onSetModelPickerOpen(false);
9926
+ return;
9927
+ }
9928
+ void onOpenModelPicker();
9899
9929
  }
9900
- void onOpenModelPicker();
9901
9930
  }
9902
- }
9903
- ),
9904
- thinkingControl ? /* @__PURE__ */ jsx35(
9905
- ThinkingSelectTrigger,
9906
- {
9907
- value: selectedThinking,
9908
- disabled: isStreaming || thinkingControlled,
9909
- trigger: "slash",
9910
- open: thinkingPickerOpen,
9911
- onClick: () => {
9912
- if (thinkingPickerOpen) {
9913
- onSetThinkingPickerOpen(false);
9914
- return;
9931
+ ),
9932
+ thinkingControl ? /* @__PURE__ */ jsx35(
9933
+ ThinkingSelectTrigger,
9934
+ {
9935
+ value: selectedThinking,
9936
+ disabled: isStreaming || thinkingControlled,
9937
+ trigger: "slash",
9938
+ open: thinkingPickerOpen,
9939
+ onClick: () => {
9940
+ if (thinkingPickerOpen) {
9941
+ onSetThinkingPickerOpen(false);
9942
+ return;
9943
+ }
9944
+ void onOpenThinkingPicker();
9915
9945
  }
9916
- void onOpenThinkingPicker();
9917
9946
  }
9918
- }
9919
- ) : null
9920
- ]
9921
- }
9922
- )
9947
+ ) : null
9948
+ ] })
9949
+ }
9950
+ )
9951
+ ] })
9923
9952
  ] });
9924
9953
  }
9925
9954
  function getHeaderValue(headers, name) {
@@ -10146,7 +10175,7 @@ function PiChatPanel({
10146
10175
  hotReloadEnabled = true,
10147
10176
  suggestions = defaultChatSuggestions,
10148
10177
  emptyState,
10149
- emptyPlacement = "default",
10178
+ emptyPlacement = "hero",
10150
10179
  composerPlaceholder,
10151
10180
  initialDraft,
10152
10181
  autoSubmitInitialDraft = false,
@@ -10905,6 +10934,78 @@ function PiChatPanel({
10905
10934
  }
10906
10935
  handleComposerKeyDown(event);
10907
10936
  }, [handleComposerKeyDown, interrupt, isStreaming, mentionState, slashQuery]);
10937
+ const selectEmptySuggestion = useCallback18((suggestion) => {
10938
+ const text = suggestion.prompt ?? suggestion.label;
10939
+ if (!text.trim()) return;
10940
+ void sendComposerMessage({ text, files: [], source: "suggestion" }).then((result) => {
10941
+ if (result === false) setComposerDraft(text);
10942
+ });
10943
+ }, [sendComposerMessage, setComposerDraft]);
10944
+ const composerSurface = /* @__PURE__ */ jsx36(
10945
+ PiChatComposerSurface,
10946
+ {
10947
+ chrome,
10948
+ pickerPlacement: emptyHero ? "above-compact" : "above",
10949
+ isStreaming,
10950
+ status,
10951
+ disabled,
10952
+ submitStatus,
10953
+ submitDisabled,
10954
+ composerBlocked,
10955
+ composerBlockerLabel,
10956
+ composerPlaceholder,
10957
+ composerStatusNotice,
10958
+ workspaceWarmupBlocked,
10959
+ primaryComposerBlocker,
10960
+ onComposerBlockerAction,
10961
+ queuePreview,
10962
+ onEditQueued: editQueued,
10963
+ hotReloadEnabled,
10964
+ pluginUpdateState,
10965
+ onDismissPluginUpdate: dismissPluginUpdate,
10966
+ onRunPluginUpdate: runPluginUpdate,
10967
+ commandNotifyState,
10968
+ onDismissCommandNotify: dismissCommandNotify,
10969
+ attachmentNotice,
10970
+ onAttachmentNotice: setAttachmentNotice,
10971
+ mentionState,
10972
+ slashQuery,
10973
+ apiBaseUrl,
10974
+ fetch: fetch2,
10975
+ requestHeaders: normalizedRequestHeaders,
10976
+ storageScope,
10977
+ onSelectMention: selectMention,
10978
+ onDismissMention: dismissMention,
10979
+ commands: allCommands,
10980
+ onSelectSlashCommand: selectSlashCommand,
10981
+ onDismissSlash: dismissSlash,
10982
+ modelPickerOpen,
10983
+ selectedModel,
10984
+ modelOptions,
10985
+ modelControlled: model !== void 0,
10986
+ hideDefaultModelOption,
10987
+ hideComposerSettings,
10988
+ onModelChange: modelDiscovery.setModel,
10989
+ onSetModelPickerOpen: setModelPickerOpen,
10990
+ onOpenModelPicker: openModelPicker,
10991
+ thinkingPickerOpen,
10992
+ selectedThinking,
10993
+ thinkingControl,
10994
+ thinkingControlled: thinkingLevel !== void 0,
10995
+ onThinkingChange: setStoredThinkingLevel,
10996
+ onSetThinkingPickerOpen: setThinkingPickerOpen,
10997
+ onOpenThinkingPicker: openThinkingPicker,
10998
+ draft,
10999
+ textareaRef,
11000
+ onTextareaChange,
11001
+ onTextareaKeyDown,
11002
+ updateDraft: (update, options) => {
11003
+ setComposerDraft(update(draftRef.current), options?.focus ?? true);
11004
+ },
11005
+ onSubmitMessage: ({ text, files }) => sendComposerMessage({ text, files }),
11006
+ onStop: stop
11007
+ }
11008
+ );
10908
11009
  return /* @__PURE__ */ jsx36(ArtifactOpenProvider, { onOpenArtifact, children: /* @__PURE__ */ jsxs31(
10909
11010
  "div",
10910
11011
  {
@@ -10940,8 +11041,8 @@ function PiChatPanel({
10940
11041
  "div",
10941
11042
  {
10942
11043
  className: cn(
10943
- "flex h-full min-h-0 flex-col overflow-hidden",
10944
- emptyHero && "justify-center",
11044
+ "flex h-full min-h-0 flex-col",
11045
+ emptyHero ? "justify-center overflow-y-auto py-6" : "overflow-hidden",
10945
11046
  chrome && "mx-3 my-3 rounded-xl bg-[color:var(--surface-chat)] shadow-[0_1px_0_oklch(0_0_0/0.02),0_1px_2px_-1px_oklch(0_0_0/0.04),inset_0_0_0_1px_oklch(from_var(--border)_l_c_h/0.6)]"
10946
11047
  ),
10947
11048
  children: [
@@ -10970,70 +11071,18 @@ function PiChatPanel({
10970
11071
  windowResetKey: activeSessionId
10971
11072
  }
10972
11073
  ),
10973
- /* @__PURE__ */ jsx36(
10974
- PiChatComposerSurface,
11074
+ composerSurface,
11075
+ emptyHero ? /* @__PURE__ */ jsxs31(
11076
+ "div",
10975
11077
  {
10976
- chrome,
10977
- isStreaming,
10978
- status,
10979
- disabled,
10980
- submitStatus,
10981
- submitDisabled,
10982
- composerBlocked,
10983
- composerBlockerLabel,
10984
- composerPlaceholder,
10985
- composerStatusNotice,
10986
- workspaceWarmupBlocked,
10987
- primaryComposerBlocker,
10988
- onComposerBlockerAction,
10989
- queuePreview,
10990
- onEditQueued: editQueued,
10991
- hotReloadEnabled,
10992
- pluginUpdateState,
10993
- onDismissPluginUpdate: dismissPluginUpdate,
10994
- onRunPluginUpdate: runPluginUpdate,
10995
- commandNotifyState,
10996
- onDismissCommandNotify: dismissCommandNotify,
10997
- attachmentNotice,
10998
- onAttachmentNotice: setAttachmentNotice,
10999
- mentionState,
11000
- slashQuery,
11001
- apiBaseUrl,
11002
- fetch: fetch2,
11003
- requestHeaders: normalizedRequestHeaders,
11004
- storageScope,
11005
- onSelectMention: selectMention,
11006
- onDismissMention: dismissMention,
11007
- commands: allCommands,
11008
- onSelectSlashCommand: selectSlashCommand,
11009
- onDismissSlash: dismissSlash,
11010
- modelPickerOpen,
11011
- selectedModel,
11012
- modelOptions,
11013
- modelControlled: model !== void 0,
11014
- hideDefaultModelOption,
11015
- hideComposerSettings,
11016
- onModelChange: modelDiscovery.setModel,
11017
- onSetModelPickerOpen: setModelPickerOpen,
11018
- onOpenModelPicker: openModelPicker,
11019
- thinkingPickerOpen,
11020
- selectedThinking,
11021
- thinkingControl,
11022
- thinkingControlled: thinkingLevel !== void 0,
11023
- onThinkingChange: setStoredThinkingLevel,
11024
- onSetThinkingPickerOpen: setThinkingPickerOpen,
11025
- onOpenThinkingPicker: openThinkingPicker,
11026
- draft,
11027
- textareaRef,
11028
- onTextareaChange,
11029
- onTextareaKeyDown,
11030
- updateDraft: (update, options) => {
11031
- setComposerDraft(update(draftRef.current), options?.focus ?? true);
11032
- },
11033
- onSubmitMessage: ({ text, files }) => sendComposerMessage({ text, files }),
11034
- onStop: stop
11078
+ "data-boring-agent-part": "empty-hero-suggestions",
11079
+ className: "@container mx-auto w-full max-w-[640px] px-2 pb-4",
11080
+ children: [
11081
+ /* @__PURE__ */ jsx36(ChatSuggestionGrid, { suggestions, onSelect: selectEmptySuggestion, className: "mt-4" }),
11082
+ emptyState?.footer
11083
+ ]
11035
11084
  }
11036
- )
11085
+ ) : null
11037
11086
  ]
11038
11087
  }
11039
11088
  ) }),