@opengeni/react 0.2.0 → 0.3.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/dist/index.js CHANGED
@@ -1566,6 +1566,21 @@ function useBillingUsage(options = {}) {
1566
1566
  };
1567
1567
  }
1568
1568
 
1569
+ // src/hooks/use-available-models.ts
1570
+ import { useCallback as useCallback14 } from "react";
1571
+ function useAvailableModels(options = {}) {
1572
+ const client = useOpenGeniClient(options);
1573
+ const load = useCallback14(async () => await client.getClientConfig(), [client]);
1574
+ const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });
1575
+ return {
1576
+ models: state.data?.models ?? [],
1577
+ defaultModel: state.data?.defaultModel ?? null,
1578
+ loading: state.loading,
1579
+ error: state.error,
1580
+ refresh: state.refresh
1581
+ };
1582
+ }
1583
+
1569
1584
  // src/approvals.ts
1570
1585
  function approvalsFromRequiresAction(payload) {
1571
1586
  const approvals = payload && typeof payload === "object" ? payload.approvals : void 0;
@@ -1798,7 +1813,7 @@ function clearErrorMessage(cause) {
1798
1813
  }
1799
1814
 
1800
1815
  // src/hooks/use-slash-commands.ts
1801
- import { useCallback as useCallback14, useMemo as useMemo3, useRef as useRef6, useState as useState7 } from "react";
1816
+ import { useCallback as useCallback15, useMemo as useMemo3, useRef as useRef6, useState as useState7 } from "react";
1802
1817
  function useSlashCommands(options) {
1803
1818
  const { commands, context, handlers, value, setValue } = options;
1804
1819
  const [highlight, setHighlight] = useState7(0);
@@ -1838,7 +1853,7 @@ function useSlashCommands(options) {
1838
1853
  const isCommandDraft = parsed !== null && items.length > 0;
1839
1854
  const clampedHighlight = items.length === 0 ? 0 : Math.min(highlight, items.length - 1);
1840
1855
  const activeArgHint = activeCommand ? argHint(activeCommand.args) : "";
1841
- const buildContext = useCallback14(
1856
+ const buildContext = useCallback15(
1842
1857
  (command) => {
1843
1858
  if (!context) {
1844
1859
  return null;
@@ -1847,7 +1862,7 @@ function useSlashCommands(options) {
1847
1862
  },
1848
1863
  [context, handlers]
1849
1864
  );
1850
- const execute = useCallback14(
1865
+ const execute = useCallback15(
1851
1866
  async (command, args) => {
1852
1867
  const ctx = buildContext(command);
1853
1868
  if (!ctx) {
@@ -1867,20 +1882,20 @@ function useSlashCommands(options) {
1867
1882
  },
1868
1883
  [buildContext, setValue]
1869
1884
  );
1870
- const autocomplete = useCallback14(
1885
+ const autocomplete = useCallback15(
1871
1886
  (command) => {
1872
1887
  setValue(`/${command.name} `);
1873
1888
  setHighlight(0);
1874
1889
  },
1875
1890
  [setValue]
1876
1891
  );
1877
- const autocompleteHighlighted = useCallback14(() => {
1892
+ const autocompleteHighlighted = useCallback15(() => {
1878
1893
  const command = items[clampedHighlight];
1879
1894
  if (command) {
1880
1895
  autocomplete(command);
1881
1896
  }
1882
1897
  }, [items, clampedHighlight, autocomplete]);
1883
- const runResolved = useCallback14(
1898
+ const runResolved = useCallback15(
1884
1899
  async (command, options2) => {
1885
1900
  if (!parsed) {
1886
1901
  return;
@@ -1903,7 +1918,7 @@ function useSlashCommands(options) {
1903
1918
  },
1904
1919
  [parsed, activeCommand, autocomplete, execute]
1905
1920
  );
1906
- const runHighlighted = useCallback14(async () => {
1921
+ const runHighlighted = useCallback15(async () => {
1907
1922
  if (!parsed) {
1908
1923
  return;
1909
1924
  }
@@ -1922,7 +1937,7 @@ function useSlashCommands(options) {
1922
1937
  }
1923
1938
  await runResolved(command);
1924
1939
  }, [parsed, activeCommand, items, clampedHighlight, runResolved]);
1925
- const runAt = useCallback14(
1940
+ const runAt = useCallback15(
1926
1941
  async (index) => {
1927
1942
  const command = items[index];
1928
1943
  if (!command) {
@@ -1933,7 +1948,7 @@ function useSlashCommands(options) {
1933
1948
  [items, runResolved]
1934
1949
  );
1935
1950
  const runningRef = useRef6(false);
1936
- const onKeyDown = useCallback14(
1951
+ const onKeyDown = useCallback15(
1937
1952
  (event) => {
1938
1953
  if (!open) {
1939
1954
  return false;
@@ -2084,8 +2099,63 @@ function CommandPalette({ open, items, highlight, onHighlight, onRun, argHintTex
2084
2099
  // src/components/chat-composer.tsx
2085
2100
  import { ArrowUpIcon, FileIcon, ImageIcon, LoaderCircleIcon, PaperclipIcon, SquareIcon, XIcon } from "lucide-react";
2086
2101
  import { AnimatePresence as AnimatePresence2, motion as motion2 } from "motion/react";
2087
- import { useCallback as useCallback15, useEffect as useEffect6, useId, useMemo as useMemo4, useRef as useRef7, useState as useState8 } from "react";
2088
- import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
2102
+ import { useCallback as useCallback16, useEffect as useEffect6, useId as useId2, useMemo as useMemo5, useRef as useRef7, useState as useState8 } from "react";
2103
+
2104
+ // src/components/model-picker.tsx
2105
+ import { ChevronDownIcon } from "lucide-react";
2106
+ import { useId, useMemo as useMemo4 } from "react";
2107
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
2108
+ function ModelPicker({ models, value, onChange, disabled, className }) {
2109
+ const selectId = useId();
2110
+ const groups = useMemo4(() => {
2111
+ const byProvider = /* @__PURE__ */ new Map();
2112
+ for (const model of models) {
2113
+ let group = byProvider.get(model.provider);
2114
+ if (!group) {
2115
+ group = { label: model.providerLabel, models: [] };
2116
+ byProvider.set(model.provider, group);
2117
+ }
2118
+ group.models.push(model);
2119
+ }
2120
+ return [...byProvider.values()];
2121
+ }, [models]);
2122
+ if (models.length === 0) {
2123
+ return null;
2124
+ }
2125
+ return /* @__PURE__ */ jsxs2("span", { className: cn("relative inline-flex items-center", className), children: [
2126
+ /* @__PURE__ */ jsx3("label", { htmlFor: selectId, className: "sr-only", children: "Model" }),
2127
+ /* @__PURE__ */ jsx3(
2128
+ "select",
2129
+ {
2130
+ id: selectId,
2131
+ value: value ?? "",
2132
+ onChange: (event) => onChange(event.target.value),
2133
+ disabled: disabled === true,
2134
+ "aria-label": "Model",
2135
+ className: cn(
2136
+ // Sized like the other footer controls; the chevron overlay needs the
2137
+ // right padding so the value never collides with it.
2138
+ "h-8 max-w-[180px] cursor-pointer appearance-none truncate rounded-og-md bg-transparent",
2139
+ "py-0 pl-2 pr-6 text-[13px] text-og-fg-muted",
2140
+ "transition-colors duration-150 hover:bg-og-surface-2 hover:text-og-fg",
2141
+ "focus:outline-none focus-visible:outline-none",
2142
+ "disabled:cursor-not-allowed disabled:opacity-50"
2143
+ ),
2144
+ children: groups.map((group) => /* @__PURE__ */ jsx3("optgroup", { label: group.label, children: group.models.map((model) => /* @__PURE__ */ jsx3("option", { value: model.id, children: model.label }, model.id)) }, group.label))
2145
+ }
2146
+ ),
2147
+ /* @__PURE__ */ jsx3(
2148
+ ChevronDownIcon,
2149
+ {
2150
+ "aria-hidden": true,
2151
+ className: "pointer-events-none absolute right-1.5 size-3.5 text-og-fg-subtle"
2152
+ }
2153
+ )
2154
+ ] });
2155
+ }
2156
+
2157
+ // src/components/chat-composer.tsx
2158
+ import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
2089
2159
  var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["queued", "running"]);
2090
2160
  function ChatComposer({
2091
2161
  composer,
@@ -2098,6 +2168,9 @@ function ChatComposer({
2098
2168
  header,
2099
2169
  onPaste,
2100
2170
  attachments,
2171
+ models,
2172
+ selectedModel,
2173
+ onSelectModel,
2101
2174
  className,
2102
2175
  commands = defaultCommands,
2103
2176
  commandContext,
@@ -2111,7 +2184,7 @@ function ChatComposer({
2111
2184
  const canSend = (composer.canSend || hasReadyAttachment) && !blockedByUpload && !composer.sending;
2112
2185
  const [dragging, setDragging] = useState8(false);
2113
2186
  const dragCarriesFiles = (event) => event.dataTransfer != null && [...event.dataTransfer.types].includes("Files");
2114
- const handleDragOver = useCallback15(
2187
+ const handleDragOver = useCallback16(
2115
2188
  (event) => {
2116
2189
  if (!attachments || !dragCarriesFiles(event)) {
2117
2190
  return;
@@ -2121,7 +2194,7 @@ function ChatComposer({
2121
2194
  },
2122
2195
  [attachments]
2123
2196
  );
2124
- const handleDragLeave = useCallback15(
2197
+ const handleDragLeave = useCallback16(
2125
2198
  (event) => {
2126
2199
  if (!attachments) {
2127
2200
  return;
@@ -2133,7 +2206,7 @@ function ChatComposer({
2133
2206
  },
2134
2207
  [attachments]
2135
2208
  );
2136
- const handleDrop = useCallback15(
2209
+ const handleDrop = useCallback16(
2137
2210
  (event) => {
2138
2211
  if (!attachments || !dragCarriesFiles(event)) {
2139
2212
  return;
@@ -2149,8 +2222,8 @@ function ChatComposer({
2149
2222
  const [notice, setNotice] = useState8(null);
2150
2223
  const [helpOpen, setHelpOpen] = useState8(false);
2151
2224
  const [confirmState, setConfirmState] = useState8(null);
2152
- const listboxId = useId();
2153
- const resize = useCallback15(() => {
2225
+ const listboxId = useId2();
2226
+ const resize = useCallback16(() => {
2154
2227
  const textarea = textareaRef.current;
2155
2228
  if (!textarea) {
2156
2229
  return;
@@ -2161,7 +2234,7 @@ function ChatComposer({
2161
2234
  useEffect6(() => {
2162
2235
  resize();
2163
2236
  }, [composer.value, resize]);
2164
- const handlers = useMemo4(
2237
+ const handlers = useMemo5(
2165
2238
  () => ({
2166
2239
  notice: (next) => {
2167
2240
  setNotice(next);
@@ -2219,14 +2292,14 @@ function ChatComposer({
2219
2292
  void composer.send();
2220
2293
  }
2221
2294
  };
2222
- const handlePaste = useCallback15(
2295
+ const handlePaste = useCallback16(
2223
2296
  (event) => {
2224
2297
  onPaste?.(event);
2225
2298
  attachments?.addFromPaste(event);
2226
2299
  },
2227
2300
  [onPaste, attachments]
2228
2301
  );
2229
- const handleFileChange = useCallback15(
2302
+ const handleFileChange = useCallback16(
2230
2303
  (event) => {
2231
2304
  if (event.target.files) {
2232
2305
  attachments?.addFiles(event.target.files);
@@ -2235,7 +2308,7 @@ function ChatComposer({
2235
2308
  },
2236
2309
  [attachments]
2237
2310
  );
2238
- const helpCommands = useMemo4(
2311
+ const helpCommands = useMemo5(
2239
2312
  () => commands.filter((command) => {
2240
2313
  if (command.permission && commandContext) {
2241
2314
  const perms = commandContext.permissions;
@@ -2246,9 +2319,9 @@ function ChatComposer({
2246
2319
  [commands, commandContext]
2247
2320
  );
2248
2321
  const activeNotice = notice ?? (composer.error ? { tone: "error", message: composer.error.message || "Sending failed \u2014 your draft is still here. Try again." } : null);
2249
- return /* @__PURE__ */ jsxs2("div", { className: cn("og-root", className), children: [
2250
- /* @__PURE__ */ jsxs2("div", { className: "relative", children: [
2251
- paletteEnabled ? /* @__PURE__ */ jsx3(
2322
+ return /* @__PURE__ */ jsxs3("div", { className: cn("og-root", className), children: [
2323
+ /* @__PURE__ */ jsxs3("div", { className: "relative", children: [
2324
+ paletteEnabled ? /* @__PURE__ */ jsx4(
2252
2325
  CommandPalette,
2253
2326
  {
2254
2327
  open: palette.open && confirmState === null,
@@ -2263,7 +2336,7 @@ function ChatComposer({
2263
2336
  listboxId
2264
2337
  }
2265
2338
  ) : null,
2266
- /* @__PURE__ */ jsxs2(
2339
+ /* @__PURE__ */ jsxs3(
2267
2340
  "div",
2268
2341
  {
2269
2342
  onDragOver: attachments ? handleDragOver : void 0,
@@ -2278,7 +2351,7 @@ function ChatComposer({
2278
2351
  dragging && "border-dashed border-og-accent"
2279
2352
  ),
2280
2353
  children: [
2281
- dragging ? /* @__PURE__ */ jsx3(
2354
+ dragging ? /* @__PURE__ */ jsx4(
2282
2355
  "div",
2283
2356
  {
2284
2357
  "aria-hidden": true,
@@ -2286,15 +2359,15 @@ function ChatComposer({
2286
2359
  "pointer-events-none absolute inset-0 z-10 flex items-center justify-center",
2287
2360
  "rounded-og-lg bg-og-surface-1/85 text-sm font-medium text-og-accent backdrop-blur-[1px]"
2288
2361
  ),
2289
- children: /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-2", children: [
2290
- /* @__PURE__ */ jsx3(PaperclipIcon, { className: "size-4" }),
2362
+ children: /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center gap-2", children: [
2363
+ /* @__PURE__ */ jsx4(PaperclipIcon, { className: "size-4" }),
2291
2364
  "Drop files to attach"
2292
2365
  ] })
2293
2366
  }
2294
2367
  ) : null,
2295
- attachments && attachments.attachments.length > 0 ? /* @__PURE__ */ jsx3(AttachmentChips, { attachments: attachments.attachments, onRemove: attachments.remove }) : null,
2368
+ attachments && attachments.attachments.length > 0 ? /* @__PURE__ */ jsx4(AttachmentChips, { attachments: attachments.attachments, onRemove: attachments.remove }) : null,
2296
2369
  header,
2297
- /* @__PURE__ */ jsx3(
2370
+ /* @__PURE__ */ jsx4(
2298
2371
  "textarea",
2299
2372
  {
2300
2373
  ref: textareaRef,
@@ -2326,17 +2399,17 @@ function ChatComposer({
2326
2399
  )
2327
2400
  }
2328
2401
  ),
2329
- confirmState && pendingDangerCommand ? /* @__PURE__ */ jsx3(
2402
+ confirmState && pendingDangerCommand ? /* @__PURE__ */ jsx4(
2330
2403
  ConfirmBar,
2331
2404
  {
2332
2405
  command: pendingDangerCommand,
2333
2406
  onCancel: () => confirmState.resolve(false),
2334
2407
  onConfirm: () => confirmState.resolve(true)
2335
2408
  }
2336
- ) : /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between gap-2 px-2.5 pb-2.5 pt-1", children: [
2337
- attachments || controlsStart ? /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center gap-1.5", children: [
2338
- attachments ? /* @__PURE__ */ jsxs2(Fragment, { children: [
2339
- /* @__PURE__ */ jsx3(
2409
+ ) : /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between gap-2 px-2.5 pb-2.5 pt-1", children: [
2410
+ attachments || models || controlsStart ? /* @__PURE__ */ jsxs3("span", { className: "flex min-w-0 items-center gap-1.5", children: [
2411
+ attachments ? /* @__PURE__ */ jsxs3(Fragment, { children: [
2412
+ /* @__PURE__ */ jsx4(
2340
2413
  "input",
2341
2414
  {
2342
2415
  ref: fileInputRef,
@@ -2346,7 +2419,7 @@ function ChatComposer({
2346
2419
  onChange: handleFileChange
2347
2420
  }
2348
2421
  ),
2349
- /* @__PURE__ */ jsx3(
2422
+ /* @__PURE__ */ jsx4(
2350
2423
  "button",
2351
2424
  {
2352
2425
  type: "button",
@@ -2359,14 +2432,23 @@ function ChatComposer({
2359
2432
  "text-og-fg-muted transition-colors duration-150 hover:bg-og-surface-2 hover:text-og-fg",
2360
2433
  "disabled:cursor-not-allowed disabled:opacity-50"
2361
2434
  ),
2362
- children: /* @__PURE__ */ jsx3(PaperclipIcon, { className: "size-4" })
2435
+ children: /* @__PURE__ */ jsx4(PaperclipIcon, { className: "size-4" })
2363
2436
  }
2364
2437
  )
2365
2438
  ] }) : null,
2439
+ models ? /* @__PURE__ */ jsx4(
2440
+ ModelPicker,
2441
+ {
2442
+ models,
2443
+ value: selectedModel,
2444
+ onChange: (modelId) => onSelectModel?.(modelId),
2445
+ disabled: disabled === true
2446
+ }
2447
+ ) : null,
2366
2448
  controlsStart
2367
- ] }) : /* @__PURE__ */ jsx3("span", { className: "px-1.5 text-[11px] text-og-fg-subtle max-sm:hidden", children: hint ?? "Enter to send \xB7 Shift+Enter for a new line \xB7 / for commands" }),
2368
- /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-1.5", children: [
2369
- /* @__PURE__ */ jsx3(AnimatePresence2, { initial: false, children: active ? /* @__PURE__ */ jsx3(
2449
+ ] }) : /* @__PURE__ */ jsx4("span", { className: "px-1.5 text-[11px] text-og-fg-subtle max-sm:hidden", children: hint ?? "Enter to send \xB7 Shift+Enter for a new line \xB7 / for commands" }),
2450
+ /* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-1.5", children: [
2451
+ /* @__PURE__ */ jsx4(AnimatePresence2, { initial: false, children: active ? /* @__PURE__ */ jsx4(
2370
2452
  motion2.button,
2371
2453
  {
2372
2454
  type: "button",
@@ -2384,11 +2466,11 @@ function ChatComposer({
2384
2466
  "hover:border-og-status-failed/50 hover:text-og-status-failed",
2385
2467
  "disabled:opacity-50"
2386
2468
  ),
2387
- children: composer.interrupting ? /* @__PURE__ */ jsx3(LoaderCircleIcon, { className: "size-3.5 animate-og-spin" }) : /* @__PURE__ */ jsx3(SquareIcon, { className: "size-3 fill-current" })
2469
+ children: composer.interrupting ? /* @__PURE__ */ jsx4(LoaderCircleIcon, { className: "size-3.5 animate-og-spin" }) : /* @__PURE__ */ jsx4(SquareIcon, { className: "size-3 fill-current" })
2388
2470
  },
2389
2471
  "stop"
2390
2472
  ) : null }),
2391
- /* @__PURE__ */ jsx3(
2473
+ /* @__PURE__ */ jsx4(
2392
2474
  "button",
2393
2475
  {
2394
2476
  type: "button",
@@ -2407,7 +2489,7 @@ function ChatComposer({
2407
2489
  "hover:bg-og-accent-strong active:scale-95",
2408
2490
  "disabled:cursor-not-allowed disabled:bg-og-surface-3 disabled:text-og-fg-subtle disabled:shadow-none"
2409
2491
  ),
2410
- children: composer.sending ? /* @__PURE__ */ jsx3(LoaderCircleIcon, { className: "size-4 animate-og-spin" }) : /* @__PURE__ */ jsx3(ArrowUpIcon, { className: "size-4" })
2492
+ children: composer.sending ? /* @__PURE__ */ jsx4(LoaderCircleIcon, { className: "size-4 animate-og-spin" }) : /* @__PURE__ */ jsx4(ArrowUpIcon, { className: "size-4" })
2411
2493
  }
2412
2494
  )
2413
2495
  ] })
@@ -2416,8 +2498,8 @@ function ChatComposer({
2416
2498
  }
2417
2499
  )
2418
2500
  ] }),
2419
- /* @__PURE__ */ jsx3(AnimatePresence2, { children: helpOpen ? /* @__PURE__ */ jsx3(HelpPanel, { commands: helpCommands, onClose: () => setHelpOpen(false) }) : null }),
2420
- /* @__PURE__ */ jsx3(AnimatePresence2, { children: activeNotice ? /* @__PURE__ */ jsx3(
2501
+ /* @__PURE__ */ jsx4(AnimatePresence2, { children: helpOpen ? /* @__PURE__ */ jsx4(HelpPanel, { commands: helpCommands, onClose: () => setHelpOpen(false) }) : null }),
2502
+ /* @__PURE__ */ jsx4(AnimatePresence2, { children: activeNotice ? /* @__PURE__ */ jsx4(
2421
2503
  motion2.p,
2422
2504
  {
2423
2505
  initial: { opacity: 0, height: 0 },
@@ -2439,7 +2521,7 @@ function ChatComposer({
2439
2521
  ] });
2440
2522
  }
2441
2523
  function ConfirmBar({ command, onCancel, onConfirm }) {
2442
- return /* @__PURE__ */ jsxs2(
2524
+ return /* @__PURE__ */ jsxs3(
2443
2525
  "div",
2444
2526
  {
2445
2527
  role: "alertdialog",
@@ -2447,17 +2529,17 @@ function ConfirmBar({ command, onCancel, onConfirm }) {
2447
2529
  "data-testid": "danger-confirm",
2448
2530
  className: "flex items-center justify-between gap-2 px-2.5 pb-2.5 pt-1",
2449
2531
  children: [
2450
- /* @__PURE__ */ jsxs2("span", { className: "px-1.5 text-[12px] text-og-status-failed", children: [
2532
+ /* @__PURE__ */ jsxs3("span", { className: "px-1.5 text-[12px] text-og-status-failed", children: [
2451
2533
  "Run ",
2452
- /* @__PURE__ */ jsxs2("span", { className: "font-mono", children: [
2534
+ /* @__PURE__ */ jsxs3("span", { className: "font-mono", children: [
2453
2535
  "/",
2454
2536
  command.name
2455
2537
  ] }),
2456
2538
  "? ",
2457
2539
  command.description
2458
2540
  ] }),
2459
- /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-1.5", children: [
2460
- /* @__PURE__ */ jsx3(
2541
+ /* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-1.5", children: [
2542
+ /* @__PURE__ */ jsx4(
2461
2543
  "button",
2462
2544
  {
2463
2545
  type: "button",
@@ -2466,7 +2548,7 @@ function ConfirmBar({ command, onCancel, onConfirm }) {
2466
2548
  children: "Cancel"
2467
2549
  }
2468
2550
  ),
2469
- /* @__PURE__ */ jsx3(
2551
+ /* @__PURE__ */ jsx4(
2470
2552
  "button",
2471
2553
  {
2472
2554
  type: "button",
@@ -2482,7 +2564,7 @@ function ConfirmBar({ command, onCancel, onConfirm }) {
2482
2564
  );
2483
2565
  }
2484
2566
  function AttachmentChips({ attachments, onRemove }) {
2485
- return /* @__PURE__ */ jsx3("div", { className: "flex flex-wrap gap-2 border-b border-og-border px-3 py-2", children: attachments.map((attachment) => /* @__PURE__ */ jsxs2(
2567
+ return /* @__PURE__ */ jsx4("div", { className: "flex flex-wrap gap-2 border-b border-og-border px-3 py-2", children: attachments.map((attachment) => /* @__PURE__ */ jsxs3(
2486
2568
  "div",
2487
2569
  {
2488
2570
  className: cn(
@@ -2490,10 +2572,10 @@ function AttachmentChips({ attachments, onRemove }) {
2490
2572
  "border-og-border bg-og-surface-2 text-xs"
2491
2573
  ),
2492
2574
  children: [
2493
- attachment.previewUrl ? /* @__PURE__ */ jsx3("img", { src: attachment.previewUrl, alt: "", className: "size-8 shrink-0 rounded object-cover" }) : attachment.contentType.startsWith("image/") ? /* @__PURE__ */ jsx3(ImageIcon, { className: "size-4 shrink-0 text-og-fg-muted" }) : /* @__PURE__ */ jsx3(FileIcon, { className: "size-4 shrink-0 text-og-fg-muted" }),
2494
- /* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
2495
- /* @__PURE__ */ jsx3("div", { className: "truncate font-medium text-og-fg", children: attachment.name }),
2496
- /* @__PURE__ */ jsx3(
2575
+ attachment.previewUrl ? /* @__PURE__ */ jsx4("img", { src: attachment.previewUrl, alt: "", className: "size-8 shrink-0 rounded object-cover" }) : attachment.contentType.startsWith("image/") ? /* @__PURE__ */ jsx4(ImageIcon, { className: "size-4 shrink-0 text-og-fg-muted" }) : /* @__PURE__ */ jsx4(FileIcon, { className: "size-4 shrink-0 text-og-fg-muted" }),
2576
+ /* @__PURE__ */ jsxs3("div", { className: "min-w-0 flex-1", children: [
2577
+ /* @__PURE__ */ jsx4("div", { className: "truncate font-medium text-og-fg", children: attachment.name }),
2578
+ /* @__PURE__ */ jsx4(
2497
2579
  "div",
2498
2580
  {
2499
2581
  className: cn(
@@ -2504,15 +2586,15 @@ function AttachmentChips({ attachments, onRemove }) {
2504
2586
  }
2505
2587
  )
2506
2588
  ] }),
2507
- attachment.status === "uploading" ? /* @__PURE__ */ jsx3(LoaderCircleIcon, { className: "size-3.5 shrink-0 animate-og-spin" }) : null,
2508
- /* @__PURE__ */ jsx3(
2589
+ attachment.status === "uploading" ? /* @__PURE__ */ jsx4(LoaderCircleIcon, { className: "size-3.5 shrink-0 animate-og-spin" }) : null,
2590
+ /* @__PURE__ */ jsx4(
2509
2591
  "button",
2510
2592
  {
2511
2593
  type: "button",
2512
2594
  onClick: () => onRemove(attachment.id),
2513
2595
  className: "shrink-0 rounded-og-xs p-1 text-og-fg-muted hover:bg-og-surface-1 hover:text-og-fg",
2514
2596
  "aria-label": `Remove ${attachment.name}`,
2515
- children: /* @__PURE__ */ jsx3(XIcon, { className: "size-3.5" })
2597
+ children: /* @__PURE__ */ jsx4(XIcon, { className: "size-3.5" })
2516
2598
  }
2517
2599
  )
2518
2600
  ]
@@ -2521,7 +2603,7 @@ function AttachmentChips({ attachments, onRemove }) {
2521
2603
  )) });
2522
2604
  }
2523
2605
  function HelpPanel({ commands, onClose }) {
2524
- return /* @__PURE__ */ jsxs2(
2606
+ return /* @__PURE__ */ jsxs3(
2525
2607
  motion2.div,
2526
2608
  {
2527
2609
  initial: { opacity: 0, height: 0 },
@@ -2529,20 +2611,20 @@ function HelpPanel({ commands, onClose }) {
2529
2611
  exit: { opacity: 0, height: 0 },
2530
2612
  className: "mt-2 overflow-hidden rounded-og-lg border border-og-border bg-og-surface-2",
2531
2613
  children: [
2532
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between border-b border-og-border px-3 py-1.5", children: [
2533
- /* @__PURE__ */ jsx3("span", { className: "text-[12px] font-medium text-og-fg", children: "Commands" }),
2534
- /* @__PURE__ */ jsx3("button", { type: "button", onClick: onClose, className: "text-[11px] text-og-fg-subtle hover:text-og-fg", children: "Close" })
2614
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between border-b border-og-border px-3 py-1.5", children: [
2615
+ /* @__PURE__ */ jsx4("span", { className: "text-[12px] font-medium text-og-fg", children: "Commands" }),
2616
+ /* @__PURE__ */ jsx4("button", { type: "button", onClick: onClose, className: "text-[11px] text-og-fg-subtle hover:text-og-fg", children: "Close" })
2535
2617
  ] }),
2536
- /* @__PURE__ */ jsx3("ul", { className: "py-1", children: commands.map((command) => {
2618
+ /* @__PURE__ */ jsx4("ul", { className: "py-1", children: commands.map((command) => {
2537
2619
  const hint = argHint(command.args);
2538
- return /* @__PURE__ */ jsxs2("li", { className: "flex items-baseline gap-2 px-3 py-1", children: [
2539
- /* @__PURE__ */ jsxs2("span", { className: "font-mono text-[12px] text-og-accent", children: [
2620
+ return /* @__PURE__ */ jsxs3("li", { className: "flex items-baseline gap-2 px-3 py-1", children: [
2621
+ /* @__PURE__ */ jsxs3("span", { className: "font-mono text-[12px] text-og-accent", children: [
2540
2622
  "/",
2541
2623
  command.name,
2542
- hint ? /* @__PURE__ */ jsx3("span", { className: "ml-1 text-og-fg-subtle", children: hint }) : null
2624
+ hint ? /* @__PURE__ */ jsx4("span", { className: "ml-1 text-og-fg-subtle", children: hint }) : null
2543
2625
  ] }),
2544
- /* @__PURE__ */ jsx3("span", { className: "text-[12px] text-og-fg-muted", children: command.description }),
2545
- command.danger ? /* @__PURE__ */ jsx3("span", { className: "ml-auto rounded-og-xs bg-og-status-failed/15 px-1 text-[10px] uppercase tracking-wide text-og-status-failed", children: "danger" }) : null
2626
+ /* @__PURE__ */ jsx4("span", { className: "text-[12px] text-og-fg-muted", children: command.description }),
2627
+ command.danger ? /* @__PURE__ */ jsx4("span", { className: "ml-auto rounded-og-xs bg-og-status-failed/15 px-1 text-[10px] uppercase tracking-wide text-og-status-failed", children: "danger" }) : null
2546
2628
  ] }, command.name);
2547
2629
  }) })
2548
2630
  ]
@@ -2562,11 +2644,94 @@ import {
2562
2644
  WrenchIcon
2563
2645
  } from "lucide-react";
2564
2646
  import { AnimatePresence as AnimatePresence3, motion as motion3 } from "motion/react";
2565
- import { useEffect as useEffect7, useMemo as useMemo5, useRef as useRef8, useState as useState9 } from "react";
2647
+ import { useEffect as useEffect7, useMemo as useMemo6, useRef as useRef8, useState as useState9 } from "react";
2566
2648
  import { Collapsible } from "radix-ui";
2567
2649
 
2650
+ // src/components/markdown.tsx
2651
+ import { memo } from "react";
2652
+ import ReactMarkdown from "react-markdown";
2653
+ import remarkGfm from "remark-gfm";
2654
+ import { jsx as jsx5 } from "react/jsx-runtime";
2655
+ var components = {
2656
+ h1: ({ children, ...props }) => /* @__PURE__ */ jsx5("h1", { className: "mt-5 mb-2.5 text-xl font-semibold tracking-tight text-og-fg first:mt-0", ...props, children }),
2657
+ h2: ({ children, ...props }) => /* @__PURE__ */ jsx5("h2", { className: "mt-5 mb-2 text-lg font-semibold tracking-tight text-og-fg first:mt-0", ...props, children }),
2658
+ h3: ({ children, ...props }) => /* @__PURE__ */ jsx5("h3", { className: "mt-4 mb-1.5 text-[15px] font-semibold tracking-tight text-og-fg first:mt-0", ...props, children }),
2659
+ h4: ({ children, ...props }) => /* @__PURE__ */ jsx5("h4", { className: "mt-4 mb-1.5 text-sm font-semibold uppercase tracking-[0.04em] text-og-fg-muted first:mt-0", ...props, children }),
2660
+ p: ({ children, ...props }) => /* @__PURE__ */ jsx5("p", { className: "my-2.5 leading-7 first:mt-0 last:mb-0", ...props, children }),
2661
+ strong: ({ children, ...props }) => /* @__PURE__ */ jsx5("strong", { className: "font-semibold text-og-fg", ...props, children }),
2662
+ em: ({ children, ...props }) => /* @__PURE__ */ jsx5("em", { className: "italic", ...props, children }),
2663
+ a: ({ children, ...props }) => /* @__PURE__ */ jsx5(
2664
+ "a",
2665
+ {
2666
+ className: "break-words font-medium text-og-accent underline-offset-2 hover:underline",
2667
+ target: "_blank",
2668
+ rel: "noreferrer noopener",
2669
+ ...props,
2670
+ children
2671
+ }
2672
+ ),
2673
+ ul: ({ children, ...props }) => /* @__PURE__ */ jsx5("ul", { className: "my-2.5 ml-5 flex list-disc flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0", ...props, children }),
2674
+ ol: ({ children, ...props }) => /* @__PURE__ */ jsx5("ol", { className: "my-2.5 ml-5 flex list-decimal flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0", ...props, children }),
2675
+ // GFM task-list items carry a leading checkbox <input>; `list-none` + a
2676
+ // negative margin pull the checkbox back to the bullet column so it aligns
2677
+ // with the text.
2678
+ li: ({ children, ...props }) => /* @__PURE__ */ jsx5("li", { className: "leading-7 marker:text-og-fg-subtle [&>ul]:my-1 [&>ol]:my-1 [&:has(>input)]:list-none [&:has(>input)]:-ml-5", ...props, children }),
2679
+ input: ({ type, ...props }) => type === "checkbox" ? /* @__PURE__ */ jsx5(
2680
+ "input",
2681
+ {
2682
+ ...props,
2683
+ type: "checkbox",
2684
+ disabled: true,
2685
+ className: "mr-2 size-3.5 translate-y-[2px] cursor-default appearance-none rounded-[3px] border border-og-border bg-og-surface-1 align-baseline checked:border-og-accent checked:bg-og-accent checked:[background-image:url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2012%2012%22%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22white%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M2.5%206.2l2.2%202.2%204.6-4.8%22%2F%3E%3C%2Fsvg%3E')] checked:bg-[length:11px_11px] checked:bg-center checked:bg-no-repeat"
2686
+ }
2687
+ ) : /* @__PURE__ */ jsx5("input", { type, ...props }),
2688
+ blockquote: ({ children, ...props }) => /* @__PURE__ */ jsx5(
2689
+ "blockquote",
2690
+ {
2691
+ className: "my-3 border-l-2 border-og-border-strong pl-3.5 text-og-fg-muted [&>p]:my-1.5 first:mt-0 last:mb-0",
2692
+ ...props,
2693
+ children
2694
+ }
2695
+ ),
2696
+ hr: (props) => /* @__PURE__ */ jsx5("hr", { className: "my-4 border-0 border-t border-og-border", ...props }),
2697
+ // Inline `code` vs fenced code blocks. react-markdown v10 no longer passes an
2698
+ // `inline` flag; a fenced block is a <code> whose parent is <pre> (styled by
2699
+ // the `pre` renderer), so a `code` reaching here is treated as inline.
2700
+ code: ({ children, className: _className, ...props }) => /* @__PURE__ */ jsx5(
2701
+ "code",
2702
+ {
2703
+ className: "rounded-og-xs border border-og-border bg-og-surface-1 px-1 py-0.5 font-og-mono text-[0.85em] text-og-fg",
2704
+ ...props,
2705
+ children
2706
+ }
2707
+ ),
2708
+ // Fenced code blocks — mirror the timeline's PayloadBlock <pre> styling for
2709
+ // visual consistency (bordered, scrollable, mono, surface background).
2710
+ pre: ({ children, ...props }) => /* @__PURE__ */ jsx5(
2711
+ "pre",
2712
+ {
2713
+ className: "my-3 max-h-96 overflow-auto rounded-og-md border border-og-border bg-og-bg/60 p-3 font-og-mono text-[12.5px] leading-5 text-og-fg-muted [&>code]:border-0 [&>code]:bg-transparent [&>code]:p-0 [&>code]:text-inherit first:mt-0 last:mb-0",
2714
+ ...props,
2715
+ children
2716
+ }
2717
+ ),
2718
+ table: ({ children, ...props }) => /* @__PURE__ */ jsx5("div", { className: "my-3 max-w-full overflow-x-auto rounded-og-md border border-og-border first:mt-0 last:mb-0", children: /* @__PURE__ */ jsx5("table", { className: "w-full border-collapse text-[13px]", ...props, children }) }),
2719
+ thead: ({ children, ...props }) => /* @__PURE__ */ jsx5("thead", { className: "bg-og-surface-1", ...props, children }),
2720
+ th: ({ children, ...props }) => /* @__PURE__ */ jsx5("th", { className: "border-b border-og-border px-3 py-1.5 text-left font-medium text-og-fg", ...props, children }),
2721
+ td: ({ children, ...props }) => /* @__PURE__ */ jsx5("td", { className: "border-b border-og-border px-3 py-1.5 align-top text-og-fg-muted [tr:last-child>&]:border-b-0", ...props, children }),
2722
+ img: ({ alt, ...props }) => /* @__PURE__ */ jsx5("img", { alt: alt ?? "", className: "my-3 max-w-full rounded-og-md border border-og-border", ...props })
2723
+ };
2724
+ function MarkdownImpl({ children, className }) {
2725
+ return (
2726
+ // `min-w-0` lets the prose shrink inside flex parents (message bubbles) so
2727
+ // long links and code blocks wrap/scroll instead of forcing overflow.
2728
+ /* @__PURE__ */ jsx5("div", { className: cn("min-w-0 break-words", className), children: /* @__PURE__ */ jsx5(ReactMarkdown, { remarkPlugins: [remarkGfm], components, children }) })
2729
+ );
2730
+ }
2731
+ var Markdown = memo(MarkdownImpl);
2732
+
2568
2733
  // src/components/session-status.tsx
2569
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
2734
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
2570
2735
  var SESSION_STATUS_META = {
2571
2736
  queued: {
2572
2737
  label: "Queued",
@@ -2607,7 +2772,7 @@ var SESSION_STATUS_META = {
2607
2772
  };
2608
2773
  function SessionStatus({ status, label, size = "md", className }) {
2609
2774
  const meta = SESSION_STATUS_META[status];
2610
- return /* @__PURE__ */ jsxs3(
2775
+ return /* @__PURE__ */ jsxs4(
2611
2776
  "span",
2612
2777
  {
2613
2778
  "data-status": status,
@@ -2618,7 +2783,7 @@ function SessionStatus({ status, label, size = "md", className }) {
2618
2783
  className
2619
2784
  ),
2620
2785
  children: [
2621
- /* @__PURE__ */ jsx4(StatusDot, { status, className: size === "sm" ? "size-1" : "size-1.5" }),
2786
+ /* @__PURE__ */ jsx6(StatusDot, { status, className: size === "sm" ? "size-1" : "size-1.5" }),
2622
2787
  label ?? meta.label
2623
2788
  ]
2624
2789
  }
@@ -2626,11 +2791,11 @@ function SessionStatus({ status, label, size = "md", className }) {
2626
2791
  }
2627
2792
  function StatusDot({ status, className }) {
2628
2793
  const meta = SESSION_STATUS_META[status];
2629
- return /* @__PURE__ */ jsx4("span", { className: cn("relative inline-flex size-1.5 shrink-0 rounded-full", meta.dotClassName, className), children: meta.pulse ? /* @__PURE__ */ jsx4("span", { className: cn("absolute inset-0 animate-og-pulse rounded-full", meta.dotClassName) }) : null });
2794
+ return /* @__PURE__ */ jsx6("span", { className: cn("relative inline-flex size-1.5 shrink-0 rounded-full", meta.dotClassName, className), children: meta.pulse ? /* @__PURE__ */ jsx6("span", { className: cn("absolute inset-0 animate-og-pulse rounded-full", meta.dotClassName) }) : null });
2630
2795
  }
2631
2796
 
2632
2797
  // src/components/message-timeline.tsx
2633
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
2798
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
2634
2799
  function MessageTimeline({
2635
2800
  events,
2636
2801
  items,
@@ -2641,8 +2806,8 @@ function MessageTimeline({
2641
2806
  emptyState,
2642
2807
  className
2643
2808
  }) {
2644
- const resolvedItems = useMemo5(() => items ?? buildTimeline(events ?? []), [items, events]);
2645
- const groups = useMemo5(() => groupTimeline(resolvedItems), [resolvedItems]);
2809
+ const resolvedItems = useMemo6(() => items ?? buildTimeline(events ?? []), [items, events]);
2810
+ const groups = useMemo6(() => groupTimeline(resolvedItems), [resolvedItems]);
2646
2811
  const scrollRef = useRef8(null);
2647
2812
  const [pinned, setPinned] = useState9(true);
2648
2813
  const lastItem = resolvedItems[resolvedItems.length - 1];
@@ -2661,15 +2826,15 @@ function MessageTimeline({
2661
2826
  }
2662
2827
  setPinned(node.scrollHeight - node.scrollTop - node.clientHeight < 48);
2663
2828
  };
2664
- return /* @__PURE__ */ jsxs4("div", { className: cn("og-root relative min-h-0", className), children: [
2665
- /* @__PURE__ */ jsx5("div", { ref: scrollRef, onScroll, className: "h-full overflow-y-auto overscroll-contain px-4 py-6 sm:px-6", children: /* @__PURE__ */ jsxs4("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: [
2666
- groups.length === 0 && !working ? emptyState ?? /* @__PURE__ */ jsx5("p", { className: "py-10 text-center text-sm text-og-fg-subtle", children: "No activity yet." }) : null,
2829
+ return /* @__PURE__ */ jsxs5("div", { className: cn("og-root relative min-h-0", className), children: [
2830
+ /* @__PURE__ */ jsx7("div", { ref: scrollRef, onScroll, className: "h-full overflow-y-auto overscroll-contain px-4 py-6 sm:px-6", children: /* @__PURE__ */ jsxs5("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: [
2831
+ groups.length === 0 && !working ? emptyState ?? /* @__PURE__ */ jsx7("p", { className: "py-10 text-center text-sm text-og-fg-subtle", children: "No activity yet." }) : null,
2667
2832
  groups.map(
2668
- (group) => group.kind === "activity" ? /* @__PURE__ */ jsx5(ActivityCluster, { items: group.items, onOpenSession }, group.id) : /* @__PURE__ */ jsx5(TimelineRow, { item: group.item, renderMessageText }, group.item.id)
2833
+ (group) => group.kind === "activity" ? /* @__PURE__ */ jsx7(ActivityCluster, { items: group.items, onOpenSession }, group.id) : /* @__PURE__ */ jsx7(TimelineRow, { item: group.item, renderMessageText }, group.item.id)
2669
2834
  ),
2670
- working ? /* @__PURE__ */ jsx5("div", { className: "animate-og-enter flex items-center gap-2 text-sm", children: /* @__PURE__ */ jsx5("span", { className: "og-shimmer-text font-medium", children: "Working\u2026" }) }) : null
2835
+ working ? /* @__PURE__ */ jsx7("div", { className: "animate-og-enter flex items-center gap-2 text-sm", children: /* @__PURE__ */ jsx7("span", { className: "og-shimmer-text font-medium", children: "Working\u2026" }) }) : null
2671
2836
  ] }) }),
2672
- /* @__PURE__ */ jsx5(AnimatePresence3, { children: !pinned && autoFollow ? /* @__PURE__ */ jsxs4(
2837
+ /* @__PURE__ */ jsx7(AnimatePresence3, { children: !pinned && autoFollow ? /* @__PURE__ */ jsxs5(
2673
2838
  motion3.button,
2674
2839
  {
2675
2840
  type: "button",
@@ -2691,7 +2856,7 @@ function MessageTimeline({
2691
2856
  "hover:border-og-border-strong"
2692
2857
  ),
2693
2858
  children: [
2694
- /* @__PURE__ */ jsx5(ArrowDownIcon, { className: "size-3.5" }),
2859
+ /* @__PURE__ */ jsx7(ArrowDownIcon, { className: "size-3.5" }),
2695
2860
  "Jump to latest"
2696
2861
  ]
2697
2862
  }
@@ -2704,15 +2869,15 @@ function TimelineRow({
2704
2869
  }) {
2705
2870
  switch (item.kind) {
2706
2871
  case "user-message":
2707
- return /* @__PURE__ */ jsx5(UserMessageRow, { item, renderMessageText });
2872
+ return /* @__PURE__ */ jsx7(UserMessageRow, { item, renderMessageText });
2708
2873
  case "agent-message":
2709
- return /* @__PURE__ */ jsx5(AgentMessageRow, { item, renderMessageText });
2874
+ return /* @__PURE__ */ jsx7(AgentMessageRow, { item, renderMessageText });
2710
2875
  case "session-status":
2711
- return /* @__PURE__ */ jsx5(SessionStatusRow, { item });
2876
+ return /* @__PURE__ */ jsx7(SessionStatusRow, { item });
2712
2877
  case "goal":
2713
- return /* @__PURE__ */ jsx5(GoalRow, { item });
2878
+ return /* @__PURE__ */ jsx7(GoalRow, { item });
2714
2879
  case "notice":
2715
- return /* @__PURE__ */ jsx5(NoticeRow, { item });
2880
+ return /* @__PURE__ */ jsx7(NoticeRow, { item });
2716
2881
  default:
2717
2882
  return null;
2718
2883
  }
@@ -2721,35 +2886,44 @@ function UserMessageRow({
2721
2886
  item,
2722
2887
  renderMessageText
2723
2888
  }) {
2724
- return /* @__PURE__ */ jsx5("div", { className: "animate-og-enter flex justify-end", children: /* @__PURE__ */ jsx5("div", { className: "max-w-[85%] rounded-og-lg rounded-br-og-xs border border-og-border bg-og-surface-2 px-4 py-2.5 text-[15px] leading-6 text-og-fg", children: renderMessageText ? renderMessageText(item.text, item) : /* @__PURE__ */ jsx5("span", { className: "whitespace-pre-wrap", children: item.text }) }) });
2889
+ return /* @__PURE__ */ jsx7("div", { className: "animate-og-enter flex justify-end", children: /* @__PURE__ */ jsx7("div", { className: "max-w-[85%] min-w-0 rounded-og-lg rounded-br-og-xs border border-og-border bg-og-surface-2 px-4 py-2.5 text-[15px] leading-6 text-og-fg", children: renderMessageText ? renderMessageText(item.text, item) : /* @__PURE__ */ jsx7(Markdown, { children: item.text }) }) });
2725
2890
  }
2726
2891
  function AgentMessageRow({
2727
2892
  item,
2728
2893
  renderMessageText
2729
2894
  }) {
2730
- return /* @__PURE__ */ jsxs4("div", { className: "animate-og-enter text-[15px] leading-7 text-og-fg", children: [
2731
- renderMessageText ? renderMessageText(item.text, item) : /* @__PURE__ */ jsx5("span", { className: "whitespace-pre-wrap", children: item.text }),
2732
- item.streaming ? /* @__PURE__ */ jsx5("span", { className: "ml-0.5 inline-block h-[1.1em] w-[2px] translate-y-[3px] animate-og-blink rounded-full bg-og-accent", "aria-hidden": true }) : null
2733
- ] });
2895
+ const caret = item.streaming ? /* @__PURE__ */ jsx7("span", { className: "ml-0.5 inline-block h-[1.1em] w-[2px] translate-y-[3px] animate-og-blink rounded-full bg-og-accent", "aria-hidden": true }) : null;
2896
+ return /* @__PURE__ */ jsx7("div", { className: "animate-og-enter min-w-0 text-[15px] leading-7 text-og-fg", children: renderMessageText ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
2897
+ renderMessageText(item.text, item),
2898
+ caret
2899
+ ] }) : (
2900
+ // While streaming, let the caret ride the end of the last rendered line:
2901
+ // the trailing block (usually a <p>) flows inline so the caret sits on
2902
+ // its baseline instead of dropping to a new line.
2903
+ /* @__PURE__ */ jsxs5("div", { className: item.streaming ? "[&_>div>:last-child]:inline" : void 0, children: [
2904
+ /* @__PURE__ */ jsx7(Markdown, { children: item.text }),
2905
+ caret
2906
+ ] })
2907
+ ) });
2734
2908
  }
2735
2909
  function SessionStatusRow({ item }) {
2736
2910
  const meta = SESSION_STATUS_META[item.status];
2737
- return /* @__PURE__ */ jsxs4("div", { className: "animate-og-enter flex items-center gap-3 text-[11px] text-og-fg-subtle", role: "status", children: [
2738
- /* @__PURE__ */ jsx5("span", { className: "h-px flex-1 bg-og-border" }),
2739
- /* @__PURE__ */ jsxs4("span", { className: "inline-flex items-center gap-1.5", children: [
2740
- /* @__PURE__ */ jsx5(StatusDot, { status: item.status, className: "size-1" }),
2911
+ return /* @__PURE__ */ jsxs5("div", { className: "animate-og-enter flex items-center gap-3 text-[11px] text-og-fg-subtle", role: "status", children: [
2912
+ /* @__PURE__ */ jsx7("span", { className: "h-px flex-1 bg-og-border" }),
2913
+ /* @__PURE__ */ jsxs5("span", { className: "inline-flex items-center gap-1.5", children: [
2914
+ /* @__PURE__ */ jsx7(StatusDot, { status: item.status, className: "size-1" }),
2741
2915
  meta.label.toLowerCase(),
2742
2916
  " \xB7 ",
2743
2917
  formatRelativeTime(item.occurredAt)
2744
2918
  ] }),
2745
- /* @__PURE__ */ jsx5("span", { className: "h-px flex-1 bg-og-border" })
2919
+ /* @__PURE__ */ jsx7("span", { className: "h-px flex-1 bg-og-border" })
2746
2920
  ] });
2747
2921
  }
2748
2922
  function GoalRow({ item }) {
2749
2923
  const label = item.action === "set" ? "Goal set" : item.action === "updated" ? "Goal updated" : item.action === "completed" ? "Goal completed" : item.action === "paused" ? "Goal paused" : item.action === "resumed" ? "Goal resumed" : "Continuing toward the goal";
2750
- return /* @__PURE__ */ jsx5("div", { className: "animate-og-enter flex justify-center", children: /* @__PURE__ */ jsxs4("span", { className: "inline-flex max-w-full items-center gap-1.5 rounded-full border border-og-border bg-og-surface-1 px-3 py-1 text-xs text-og-fg-muted", children: [
2751
- /* @__PURE__ */ jsx5(TargetIcon, { className: "size-3.5 shrink-0 text-og-accent" }),
2752
- /* @__PURE__ */ jsxs4("span", { className: "truncate", children: [
2924
+ return /* @__PURE__ */ jsx7("div", { className: "animate-og-enter flex justify-center", children: /* @__PURE__ */ jsxs5("span", { className: "inline-flex max-w-full items-center gap-1.5 rounded-full border border-og-border bg-og-surface-1 px-3 py-1 text-xs text-og-fg-muted", children: [
2925
+ /* @__PURE__ */ jsx7(TargetIcon, { className: "size-3.5 shrink-0 text-og-accent" }),
2926
+ /* @__PURE__ */ jsxs5("span", { className: "truncate", children: [
2753
2927
  label,
2754
2928
  item.text ? `: ${truncate(item.text, 90)}` : ""
2755
2929
  ] })
@@ -2757,25 +2931,25 @@ function GoalRow({ item }) {
2757
2931
  }
2758
2932
  function NoticeRow({ item }) {
2759
2933
  const tone = item.tone === "failed" ? "border-og-status-failed/35 bg-og-status-failed/10 text-og-status-failed" : item.tone === "waiting" ? "border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting" : "border-og-border bg-og-surface-1 text-og-fg-muted";
2760
- return /* @__PURE__ */ jsxs4("div", { className: cn("animate-og-enter flex items-start gap-2.5 rounded-og-md border px-3.5 py-2.5 text-sm", tone), role: "status", children: [
2761
- /* @__PURE__ */ jsx5(TriangleAlertIcon, { className: cn("mt-0.5 size-4 shrink-0", item.tone === "cancelled" && "opacity-60") }),
2762
- /* @__PURE__ */ jsx5("span", { className: "min-w-0 whitespace-pre-wrap break-words", children: item.text })
2934
+ return /* @__PURE__ */ jsxs5("div", { className: cn("animate-og-enter flex items-start gap-2.5 rounded-og-md border px-3.5 py-2.5 text-sm", tone), role: "status", children: [
2935
+ /* @__PURE__ */ jsx7(TriangleAlertIcon, { className: cn("mt-0.5 size-4 shrink-0", item.tone === "cancelled" && "opacity-60") }),
2936
+ /* @__PURE__ */ jsx7("span", { className: "min-w-0 whitespace-pre-wrap break-words", children: item.text })
2763
2937
  ] });
2764
2938
  }
2765
2939
  function ActivityCluster({
2766
2940
  items,
2767
2941
  onOpenSession
2768
2942
  }) {
2769
- return /* @__PURE__ */ jsx5("div", { className: "animate-og-enter flex flex-col gap-1.5 border-l-2 border-og-border pl-3 sm:pl-4", children: items.map((item) => {
2943
+ return /* @__PURE__ */ jsx7("div", { className: "animate-og-enter flex flex-col gap-1.5 border-l-2 border-og-border pl-3 sm:pl-4", children: items.map((item) => {
2770
2944
  switch (item.kind) {
2771
2945
  case "reasoning":
2772
- return /* @__PURE__ */ jsx5(ReasoningRow, { item }, item.id);
2946
+ return /* @__PURE__ */ jsx7(ReasoningRow, { item }, item.id);
2773
2947
  case "tool-call":
2774
- return /* @__PURE__ */ jsx5(ToolCallRow, { item }, item.id);
2948
+ return /* @__PURE__ */ jsx7(ToolCallRow, { item }, item.id);
2775
2949
  case "worker":
2776
- return /* @__PURE__ */ jsx5(WorkerRow, { item, onOpenSession }, item.id);
2950
+ return /* @__PURE__ */ jsx7(WorkerRow, { item, onOpenSession }, item.id);
2777
2951
  case "sandbox":
2778
- return /* @__PURE__ */ jsx5(SandboxRow, { item }, item.id);
2952
+ return /* @__PURE__ */ jsx7(SandboxRow, { item }, item.id);
2779
2953
  }
2780
2954
  }) });
2781
2955
  }
@@ -2788,8 +2962,8 @@ function ActivityDisclosure({
2788
2962
  children
2789
2963
  }) {
2790
2964
  const [open, setOpen] = useState9(false);
2791
- return /* @__PURE__ */ jsxs4(Collapsible.Root, { open, onOpenChange: setOpen, children: [
2792
- /* @__PURE__ */ jsxs4(
2965
+ return /* @__PURE__ */ jsxs5(Collapsible.Root, { open, onOpenChange: setOpen, children: [
2966
+ /* @__PURE__ */ jsxs5(
2793
2967
  Collapsible.Trigger,
2794
2968
  {
2795
2969
  className: cn(
@@ -2797,15 +2971,15 @@ function ActivityDisclosure({
2797
2971
  "text-og-fg-muted transition-colors duration-150 hover:bg-og-surface-1 hover:text-og-fg"
2798
2972
  ),
2799
2973
  children: [
2800
- /* @__PURE__ */ jsx5(ChevronRightIcon, { className: "size-3.5 shrink-0 text-og-fg-subtle transition-transform duration-150 group-data-[state=open]:rotate-90" }),
2801
- /* @__PURE__ */ jsx5("span", { className: cn("shrink-0", failed ? "text-og-status-failed" : running ? "text-og-status-running" : "text-og-fg-subtle"), children: icon }),
2802
- /* @__PURE__ */ jsx5("span", { className: cn("shrink-0 font-medium", running && "og-shimmer-text", failed && "text-og-status-failed"), children: title }),
2803
- preview ? /* @__PURE__ */ jsx5("span", { className: "min-w-0 flex-1 truncate font-og-mono text-xs text-og-fg-subtle", children: preview }) : null,
2804
- running ? /* @__PURE__ */ jsx5("span", { className: "ml-auto size-1.5 shrink-0 animate-og-pulse rounded-full bg-og-status-running" }) : null
2974
+ /* @__PURE__ */ jsx7(ChevronRightIcon, { className: "size-3.5 shrink-0 text-og-fg-subtle transition-transform duration-150 group-data-[state=open]:rotate-90" }),
2975
+ /* @__PURE__ */ jsx7("span", { className: cn("shrink-0", failed ? "text-og-status-failed" : running ? "text-og-status-running" : "text-og-fg-subtle"), children: icon }),
2976
+ /* @__PURE__ */ jsx7("span", { className: cn("shrink-0 font-medium", running && "og-shimmer-text", failed && "text-og-status-failed"), children: title }),
2977
+ preview ? /* @__PURE__ */ jsx7("span", { className: "min-w-0 flex-1 truncate font-og-mono text-xs text-og-fg-subtle", children: preview }) : null,
2978
+ running ? /* @__PURE__ */ jsx7("span", { className: "ml-auto size-1.5 shrink-0 animate-og-pulse rounded-full bg-og-status-running" }) : null
2805
2979
  ]
2806
2980
  }
2807
2981
  ),
2808
- /* @__PURE__ */ jsx5(Collapsible.Content, { className: "overflow-hidden", children: /* @__PURE__ */ jsx5("div", { className: "mt-1 mb-1.5 ml-7 flex flex-col gap-2", children }) })
2982
+ /* @__PURE__ */ jsx7(Collapsible.Content, { className: "overflow-hidden", children: /* @__PURE__ */ jsx7("div", { className: "mt-1 mb-1.5 ml-7 flex flex-col gap-2", children }) })
2809
2983
  ] });
2810
2984
  }
2811
2985
  function PayloadBlock({ label, value }) {
@@ -2813,50 +2987,50 @@ function PayloadBlock({ label, value }) {
2813
2987
  if (!text) {
2814
2988
  return null;
2815
2989
  }
2816
- return /* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
2817
- /* @__PURE__ */ jsx5("p", { className: "mb-1 text-[10px] font-medium uppercase tracking-[0.08em] text-og-fg-subtle", children: label }),
2818
- /* @__PURE__ */ jsx5("pre", { className: "max-h-64 overflow-auto rounded-og-sm border border-og-border bg-og-bg/60 p-2.5 font-og-mono text-xs leading-5 text-og-fg-muted", children: text })
2990
+ return /* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
2991
+ /* @__PURE__ */ jsx7("p", { className: "mb-1 text-[10px] font-medium uppercase tracking-[0.08em] text-og-fg-subtle", children: label }),
2992
+ /* @__PURE__ */ jsx7("pre", { className: "max-h-64 overflow-auto rounded-og-sm border border-og-border bg-og-bg/60 p-2.5 font-og-mono text-xs leading-5 text-og-fg-muted", children: text })
2819
2993
  ] });
2820
2994
  }
2821
2995
  function ReasoningRow({ item }) {
2822
- return /* @__PURE__ */ jsx5(
2996
+ return /* @__PURE__ */ jsx7(
2823
2997
  ActivityDisclosure,
2824
2998
  {
2825
- icon: /* @__PURE__ */ jsx5(BrainIcon, { className: "size-3.5" }),
2999
+ icon: /* @__PURE__ */ jsx7(BrainIcon, { className: "size-3.5" }),
2826
3000
  title: item.streaming ? "Thinking" : "Thought",
2827
3001
  running: item.streaming,
2828
3002
  preview: truncate(item.text, 110),
2829
- children: /* @__PURE__ */ jsx5("p", { className: "whitespace-pre-wrap text-[13px] leading-6 text-og-fg-muted", children: item.text })
3003
+ children: /* @__PURE__ */ jsx7("p", { className: "whitespace-pre-wrap text-[13px] leading-6 text-og-fg-muted", children: item.text })
2830
3004
  }
2831
3005
  );
2832
3006
  }
2833
3007
  function ToolCallRow({ item }) {
2834
- return /* @__PURE__ */ jsxs4(
3008
+ return /* @__PURE__ */ jsxs5(
2835
3009
  ActivityDisclosure,
2836
3010
  {
2837
- icon: /* @__PURE__ */ jsx5(WrenchIcon, { className: "size-3.5" }),
3011
+ icon: /* @__PURE__ */ jsx7(WrenchIcon, { className: "size-3.5" }),
2838
3012
  title: toolDisplayName(item.name),
2839
3013
  running: item.status === "running",
2840
3014
  preview: compactPayloadPreview(item.arguments),
2841
3015
  children: [
2842
- /* @__PURE__ */ jsx5(PayloadBlock, { label: "Arguments", value: item.arguments }),
2843
- item.status === "complete" ? /* @__PURE__ */ jsx5(PayloadBlock, { label: "Output", value: item.output }) : null
3016
+ /* @__PURE__ */ jsx7(PayloadBlock, { label: "Arguments", value: item.arguments }),
3017
+ item.status === "complete" ? /* @__PURE__ */ jsx7(PayloadBlock, { label: "Output", value: item.output }) : null
2844
3018
  ]
2845
3019
  }
2846
3020
  );
2847
3021
  }
2848
3022
  function SandboxRow({ item }) {
2849
- return /* @__PURE__ */ jsxs4(
3023
+ return /* @__PURE__ */ jsxs5(
2850
3024
  ActivityDisclosure,
2851
3025
  {
2852
- icon: /* @__PURE__ */ jsx5(SquareTerminalIcon, { className: "size-3.5" }),
3026
+ icon: /* @__PURE__ */ jsx7(SquareTerminalIcon, { className: "size-3.5" }),
2853
3027
  title: toolDisplayName(item.name),
2854
3028
  running: item.status === "running",
2855
3029
  failed: item.status === "failed",
2856
3030
  preview: item.command ?? void 0,
2857
3031
  children: [
2858
- item.command ? /* @__PURE__ */ jsx5(PayloadBlock, { label: "Command", value: item.command }) : null,
2859
- item.output ? /* @__PURE__ */ jsx5(PayloadBlock, { label: "Output", value: item.output }) : null
3032
+ item.command ? /* @__PURE__ */ jsx7(PayloadBlock, { label: "Command", value: item.command }) : null,
3033
+ item.output ? /* @__PURE__ */ jsx7(PayloadBlock, { label: "Output", value: item.output }) : null
2860
3034
  ]
2861
3035
  }
2862
3036
  );
@@ -2864,26 +3038,26 @@ function SandboxRow({ item }) {
2864
3038
  function WorkerRow({ item, onOpenSession }) {
2865
3039
  const running = item.status === "running";
2866
3040
  const title = item.action === "spawn" ? running ? "Spawning worker" : "Worker spawned" : running ? "Messaging worker" : "Worker messaged";
2867
- return /* @__PURE__ */ jsxs4("div", { className: "my-0.5 flex items-start gap-3 rounded-og-md border border-og-border bg-og-surface-1 p-3 shadow-og-sm", children: [
2868
- /* @__PURE__ */ jsx5(
3041
+ return /* @__PURE__ */ jsxs5("div", { className: "my-0.5 flex items-start gap-3 rounded-og-md border border-og-border bg-og-surface-1 p-3 shadow-og-sm", children: [
3042
+ /* @__PURE__ */ jsx7(
2869
3043
  "span",
2870
3044
  {
2871
3045
  className: cn(
2872
3046
  "mt-0.5 inline-flex size-7 shrink-0 items-center justify-center rounded-og-sm",
2873
3047
  "bg-og-accent-soft text-og-accent"
2874
3048
  ),
2875
- children: /* @__PURE__ */ jsx5(BotIcon, { className: "size-4" })
3049
+ children: /* @__PURE__ */ jsx7(BotIcon, { className: "size-4" })
2876
3050
  }
2877
3051
  ),
2878
- /* @__PURE__ */ jsxs4("div", { className: "min-w-0 flex-1", children: [
2879
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
2880
- /* @__PURE__ */ jsx5("span", { className: cn("text-[13px] font-medium", running ? "og-shimmer-text" : "text-og-fg"), children: title }),
2881
- running ? /* @__PURE__ */ jsx5("span", { className: "size-1.5 animate-og-pulse rounded-full bg-og-status-running" }) : null
3052
+ /* @__PURE__ */ jsxs5("div", { className: "min-w-0 flex-1", children: [
3053
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
3054
+ /* @__PURE__ */ jsx7("span", { className: cn("text-[13px] font-medium", running ? "og-shimmer-text" : "text-og-fg"), children: title }),
3055
+ running ? /* @__PURE__ */ jsx7("span", { className: "size-1.5 animate-og-pulse rounded-full bg-og-status-running" }) : null
2882
3056
  ] }),
2883
- item.prompt ? /* @__PURE__ */ jsx5("p", { className: "mt-0.5 truncate text-xs text-og-fg-muted", children: truncate(item.prompt, 140) }) : null,
2884
- item.workerSessionId ? /* @__PURE__ */ jsx5("p", { className: "mt-1 font-og-mono text-[11px] text-og-fg-subtle", children: item.workerSessionId.slice(0, 8) }) : null
3057
+ item.prompt ? /* @__PURE__ */ jsx7("p", { className: "mt-0.5 truncate text-xs text-og-fg-muted", children: truncate(item.prompt, 140) }) : null,
3058
+ item.workerSessionId ? /* @__PURE__ */ jsx7("p", { className: "mt-1 font-og-mono text-[11px] text-og-fg-subtle", children: item.workerSessionId.slice(0, 8) }) : null
2885
3059
  ] }),
2886
- item.workerSessionId && onOpenSession ? /* @__PURE__ */ jsx5(
3060
+ item.workerSessionId && onOpenSession ? /* @__PURE__ */ jsx7(
2887
3061
  "button",
2888
3062
  {
2889
3063
  type: "button",
@@ -2899,7 +3073,7 @@ function WorkerRow({ item, onOpenSession }) {
2899
3073
  }
2900
3074
 
2901
3075
  // src/components/fleet-tile.tsx
2902
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
3076
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
2903
3077
  function sessionDisplayTitle(session) {
2904
3078
  for (const key of ["title", "name"]) {
2905
3079
  const value = session.metadata[key];
@@ -2912,7 +3086,7 @@ function sessionDisplayTitle(session) {
2912
3086
  function FleetTile({ session, title, subtitle, onOpen, className }) {
2913
3087
  const running = session.status === "running" || session.status === "queued";
2914
3088
  const needsYou = session.status === "requires_action";
2915
- return /* @__PURE__ */ jsxs5(
3089
+ return /* @__PURE__ */ jsxs6(
2916
3090
  "button",
2917
3091
  {
2918
3092
  type: "button",
@@ -2928,7 +3102,7 @@ function FleetTile({ session, title, subtitle, onOpen, className }) {
2928
3102
  className
2929
3103
  ),
2930
3104
  children: [
2931
- /* @__PURE__ */ jsx6(
3105
+ /* @__PURE__ */ jsx8(
2932
3106
  "span",
2933
3107
  {
2934
3108
  "aria-hidden": true,
@@ -2938,16 +3112,16 @@ function FleetTile({ session, title, subtitle, onOpen, className }) {
2938
3112
  )
2939
3113
  }
2940
3114
  ),
2941
- /* @__PURE__ */ jsxs5("span", { className: "flex w-full items-start justify-between gap-3", children: [
2942
- /* @__PURE__ */ jsx6("span", { className: "line-clamp-2 min-w-0 text-sm font-medium leading-snug text-og-fg", children: title ?? sessionDisplayTitle(session) }),
2943
- /* @__PURE__ */ jsx6(SessionStatus, { status: session.status, size: "sm", className: "mt-px" })
3115
+ /* @__PURE__ */ jsxs6("span", { className: "flex w-full items-start justify-between gap-3", children: [
3116
+ /* @__PURE__ */ jsx8("span", { className: "line-clamp-2 min-w-0 text-sm font-medium leading-snug text-og-fg", children: title ?? sessionDisplayTitle(session) }),
3117
+ /* @__PURE__ */ jsx8(SessionStatus, { status: session.status, size: "sm", className: "mt-px" })
2944
3118
  ] }),
2945
- subtitle ? /* @__PURE__ */ jsx6("span", { className: "line-clamp-1 text-xs text-og-fg-muted", children: subtitle }) : null,
2946
- /* @__PURE__ */ jsxs5("span", { className: "mt-auto flex w-full items-center gap-2 text-[11px] text-og-fg-subtle", children: [
2947
- /* @__PURE__ */ jsx6("span", { className: "font-og-mono", children: session.id.slice(0, 8) }),
2948
- /* @__PURE__ */ jsx6("span", { "aria-hidden": true, children: "\xB7" }),
2949
- /* @__PURE__ */ jsx6("span", { className: "truncate", children: session.model }),
2950
- /* @__PURE__ */ jsx6("span", { className: "ml-auto shrink-0", title: session.updatedAt, children: formatRelativeTime(session.updatedAt) })
3119
+ subtitle ? /* @__PURE__ */ jsx8("span", { className: "line-clamp-1 text-xs text-og-fg-muted", children: subtitle }) : null,
3120
+ /* @__PURE__ */ jsxs6("span", { className: "mt-auto flex w-full items-center gap-2 text-[11px] text-og-fg-subtle", children: [
3121
+ /* @__PURE__ */ jsx8("span", { className: "font-og-mono", children: session.id.slice(0, 8) }),
3122
+ /* @__PURE__ */ jsx8("span", { "aria-hidden": true, children: "\xB7" }),
3123
+ /* @__PURE__ */ jsx8("span", { className: "truncate", children: session.model }),
3124
+ /* @__PURE__ */ jsx8("span", { className: "ml-auto shrink-0", title: session.updatedAt, children: formatRelativeTime(session.updatedAt) })
2951
3125
  ] })
2952
3126
  ]
2953
3127
  }
@@ -2957,7 +3131,9 @@ export {
2957
3131
  ChatComposer,
2958
3132
  CommandPalette,
2959
3133
  FleetTile,
3134
+ Markdown,
2960
3135
  MessageTimeline,
3136
+ ModelPicker,
2961
3137
  OpenGeniProvider,
2962
3138
  SESSION_STATUS_META,
2963
3139
  SessionStatus,
@@ -2993,6 +3169,7 @@ export {
2993
3169
  toolDisplayName,
2994
3170
  truncate,
2995
3171
  tryParseJson,
3172
+ useAvailableModels,
2996
3173
  useBillingUsage,
2997
3174
  useComposer,
2998
3175
  useEnvironments,