@truefoundry/trueforge-ui 0.3.0-rc.2 → 0.3.0-rc.3

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.
Files changed (107) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +17 -9
  3. package/dist/{AgentCodeSnippets-637HQUXD.js → AgentCodeSnippets-N546FNNS.js} +38 -23
  4. package/dist/AgentCodeSnippets-N546FNNS.js.map +1 -0
  5. package/dist/AgentMetricChart-YWJYVYYA.js +15 -0
  6. package/dist/{AgentOverview-3FJ5EE6N.js → AgentOverview-VF74XC7I.js} +7 -7
  7. package/dist/{AgentSessionEventTimeline-VELWUYPR.js → AgentSessionEventTimeline-RFR6LQMY.js} +8 -8
  8. package/dist/{AgentSessionEventTimeline-VELWUYPR.js.map → AgentSessionEventTimeline-RFR6LQMY.js.map} +1 -1
  9. package/dist/{AgentSessionEventTimelineChart-CUKETHWM.js → AgentSessionEventTimelineChart-27CQF6FX.js} +12 -12
  10. package/dist/AgentSessionEventTimelineChart-27CQF6FX.js.map +1 -0
  11. package/dist/{AgentSessions-T7MOGOTZ.js → AgentSessions-4IVX2SGD.js} +36 -12
  12. package/dist/AgentSessions-4IVX2SGD.js.map +1 -0
  13. package/dist/{ConnectorSettings-ESZ2RSRG.js → ConnectorSettings-R5VEP7BO.js} +156 -116
  14. package/dist/ConnectorSettings-R5VEP7BO.js.map +1 -0
  15. package/dist/{DockLayout-NLFNU6F2.js → DockLayout-F44RWGEY.js} +10 -10
  16. package/dist/{DrawerLayout-PR3SMKA6.js → DrawerLayout-SQ323AVM.js} +13 -11
  17. package/dist/DrawerLayout-SQ323AVM.js.map +1 -0
  18. package/dist/{ModelSettings-LYW64IRR.js → ModelSettings-6QLS63HM.js} +10 -10
  19. package/dist/{ModelSettings-LYW64IRR.js.map → ModelSettings-6QLS63HM.js.map} +1 -1
  20. package/dist/OpenUiFenceBlock-4ROX3G4X.js +9 -0
  21. package/dist/{SandboxSettings-DF64LHYI.js → SandboxSettings-OLKDXIQS.js} +9 -9
  22. package/dist/SchedulesPage-TMOTK6DR.js +15 -0
  23. package/dist/{SettingsBuilder-LSXK2VN4.js → SettingsBuilder-GISAH2WU.js} +8 -8
  24. package/dist/{ShellRouteSync-B22IAV2W.js → ShellRouteSync-EN33DUQ7.js} +157 -22
  25. package/dist/ShellRouteSync-EN33DUQ7.js.map +1 -0
  26. package/dist/{SidebarLayout-XW6LXB7R.js → SidebarLayout-35K4AKTC.js} +74 -53
  27. package/dist/SidebarLayout-35K4AKTC.js.map +1 -0
  28. package/dist/{SkillSettings-64VXUO6J.js → SkillSettings-JSX2BTII.js} +18 -13
  29. package/dist/SkillSettings-JSX2BTII.js.map +1 -0
  30. package/dist/{TrueForgeUIWithRouter-3TSLV22Q.js → TrueForgeUIWithRouter-6VCR7ES3.js} +9 -9
  31. package/dist/{WidgetLayout-Q5P7PYSJ.js → WidgetLayout-RKBSN2FZ.js} +10 -10
  32. package/dist/{chunk-YQO2NMJ3.js → chunk-2O5EJ6QS.js} +4096 -2825
  33. package/dist/chunk-2O5EJ6QS.js.map +1 -0
  34. package/dist/chunk-6WCIL3H2.js +517 -0
  35. package/dist/chunk-6WCIL3H2.js.map +1 -0
  36. package/dist/{chunk-SQGT43Z3.js → chunk-73FQVITT.js} +21 -4
  37. package/dist/chunk-73FQVITT.js.map +1 -0
  38. package/dist/{chunk-QC42MLAK.js → chunk-7AAO4UDQ.js} +4 -3
  39. package/dist/chunk-7AAO4UDQ.js.map +1 -0
  40. package/dist/{chunk-LGRHHFHN.js → chunk-F5QVQIBH.js} +166 -45
  41. package/dist/chunk-F5QVQIBH.js.map +1 -0
  42. package/dist/{chunk-I3AL54MA.js → chunk-GIPFF6FZ.js} +28 -24
  43. package/dist/chunk-GIPFF6FZ.js.map +1 -0
  44. package/dist/{chunk-GXYAOAK5.js → chunk-GSJAYYLR.js} +219 -162
  45. package/dist/chunk-GSJAYYLR.js.map +1 -0
  46. package/dist/{chunk-VJ7BZGAF.js → chunk-J5BPHEDT.js} +2 -2
  47. package/dist/chunk-KR7WYHVF.js +195 -0
  48. package/dist/chunk-KR7WYHVF.js.map +1 -0
  49. package/dist/{chunk-VUMGMGKZ.js → chunk-LUG7E6BL.js} +52 -8
  50. package/dist/chunk-LUG7E6BL.js.map +1 -0
  51. package/dist/chunk-LXJMINS6.js +587 -0
  52. package/dist/chunk-LXJMINS6.js.map +1 -0
  53. package/dist/{chunk-FQK2XVVE.js → chunk-PT4EENB3.js} +224 -72
  54. package/dist/chunk-PT4EENB3.js.map +1 -0
  55. package/dist/{chunk-H6WTY5PM.js → chunk-Q6TCT7ZJ.js} +17 -227
  56. package/dist/chunk-Q6TCT7ZJ.js.map +1 -0
  57. package/dist/{chunk-5I2COQNL.js → chunk-XLFOXQKZ.js} +13 -11
  58. package/dist/chunk-XLFOXQKZ.js.map +1 -0
  59. package/dist/{chunk-G2TUAD65.js → chunk-XY6LZQES.js} +235 -108
  60. package/dist/chunk-XY6LZQES.js.map +1 -0
  61. package/dist/{createTrueFoundryServer-CmZnBh_l.d.ts → createTrueFoundryServer-B_FYhSdn.d.ts} +8 -5
  62. package/dist/index.d.ts +291 -89
  63. package/dist/index.js +63 -488
  64. package/dist/index.js.map +1 -1
  65. package/dist/plugins/trueforge-agent-server-adapter/index.d.ts +36 -13
  66. package/dist/plugins/trueforge-agent-server-adapter/index.js +69 -35
  67. package/dist/plugins/trueforge-agent-server-adapter/index.js.map +1 -1
  68. package/dist/styles.css +1 -1
  69. package/package.json +3 -3
  70. package/dist/AgentCodeSnippets-637HQUXD.js.map +0 -1
  71. package/dist/AgentMetricChart-4FYECRIN.js +0 -15
  72. package/dist/AgentSessionEventTimelineChart-CUKETHWM.js.map +0 -1
  73. package/dist/AgentSessions-T7MOGOTZ.js.map +0 -1
  74. package/dist/ConnectorSettings-ESZ2RSRG.js.map +0 -1
  75. package/dist/DrawerLayout-PR3SMKA6.js.map +0 -1
  76. package/dist/OpenUiFenceBlock-JEPNPJ7U.js +0 -9
  77. package/dist/SchedulesPage-WQU4H25F.js +0 -15
  78. package/dist/ShellRouteSync-B22IAV2W.js.map +0 -1
  79. package/dist/SidebarLayout-XW6LXB7R.js.map +0 -1
  80. package/dist/SkillSettings-64VXUO6J.js.map +0 -1
  81. package/dist/chunk-5I2COQNL.js.map +0 -1
  82. package/dist/chunk-BWHOZFIV.js +0 -587
  83. package/dist/chunk-BWHOZFIV.js.map +0 -1
  84. package/dist/chunk-FQK2XVVE.js.map +0 -1
  85. package/dist/chunk-G2TUAD65.js.map +0 -1
  86. package/dist/chunk-GXYAOAK5.js.map +0 -1
  87. package/dist/chunk-H6WTY5PM.js.map +0 -1
  88. package/dist/chunk-I3AL54MA.js.map +0 -1
  89. package/dist/chunk-LGRHHFHN.js.map +0 -1
  90. package/dist/chunk-NHHSZB5N.js +0 -74
  91. package/dist/chunk-NHHSZB5N.js.map +0 -1
  92. package/dist/chunk-QC42MLAK.js.map +0 -1
  93. package/dist/chunk-SFZNIO6U.js +0 -18
  94. package/dist/chunk-SFZNIO6U.js.map +0 -1
  95. package/dist/chunk-SQGT43Z3.js.map +0 -1
  96. package/dist/chunk-VUMGMGKZ.js.map +0 -1
  97. package/dist/chunk-YQO2NMJ3.js.map +0 -1
  98. /package/dist/{AgentMetricChart-4FYECRIN.js.map → AgentMetricChart-YWJYVYYA.js.map} +0 -0
  99. /package/dist/{AgentOverview-3FJ5EE6N.js.map → AgentOverview-VF74XC7I.js.map} +0 -0
  100. /package/dist/{DockLayout-NLFNU6F2.js.map → DockLayout-F44RWGEY.js.map} +0 -0
  101. /package/dist/{OpenUiFenceBlock-JEPNPJ7U.js.map → OpenUiFenceBlock-4ROX3G4X.js.map} +0 -0
  102. /package/dist/{SandboxSettings-DF64LHYI.js.map → SandboxSettings-OLKDXIQS.js.map} +0 -0
  103. /package/dist/{SchedulesPage-WQU4H25F.js.map → SchedulesPage-TMOTK6DR.js.map} +0 -0
  104. /package/dist/{SettingsBuilder-LSXK2VN4.js.map → SettingsBuilder-GISAH2WU.js.map} +0 -0
  105. /package/dist/{TrueForgeUIWithRouter-3TSLV22Q.js.map → TrueForgeUIWithRouter-6VCR7ES3.js.map} +0 -0
  106. /package/dist/{WidgetLayout-Q5P7PYSJ.js.map → WidgetLayout-RKBSN2FZ.js.map} +0 -0
  107. /package/dist/{chunk-VJ7BZGAF.js.map → chunk-J5BPHEDT.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,55 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0-rc.3
4
+
5
+ ### Minor Changes
6
+
7
+ - 1d31116: Open agent model settings inline and support typed custom model parameters.
8
+ - 74eae6c: Remove pagination from list MCP servers across the API, SDK, and UI; return and search the complete configured MCP catalog client-side.
9
+ - 12b02ff: Open Runtime Config in a right-side drawer and label scheduled sessions consistently.
10
+ - 7e25f68: Open Save Agent in a right-side drawer with only the agent name while preserving configuration from Agent Config.
11
+ - f8b5eeb: Add optional resource permissions and gate agent, schedule, and session mutations.
12
+
13
+ ### Patch Changes
14
+
15
+ - 762ecc0: TrueFoundry skills catalog: proxy GET /skills and /skills/versions from ServiceFoundry; settings skill writes return 424. SkillManifest is a type-discriminated oneOf of GitSkill | TrueFoundryRegistrySkill (`type: truefoundry`; name is FQN, display_name is short). AvailableSkill exposes optional metadata (display_name, repository_name, version). AgentSpec skill refs allow opaque FQN names, optional preload (registry), and max 50. UI draft skill mounts map catalog `id` to AgentSpec `name`.
16
+ - 26a9b80: Add an agent-scoped Schedules tab and route library schedule actions into it.
17
+ - 1b8a3f7: Add documentation links to the code snippets view and shell actions.
18
+ - d2fdfc9: Add agent-filtered chat history labels, preserve Try Agent and explicit history-filter intent in URL query state while resolving backend IDs, reset active chats when users change filters, keep Try Agent highlighted as chat, and route fresh agent builders at `/build-agent` before their session URL is assigned.
19
+ - 26a9b80: Allow sending user messages that contain attachments without text.
20
+ - 26a9b80: Add an empty state and Build Agent action to the schedule agent picker.
21
+ - 4c522e2: Bump `@truefoundry/assistant-ui-runtime` to `0.1.30`.
22
+ - 4c522e2: Bump `@truefoundry/assistant-ui-runtime` to `0.1.31`.
23
+ - d719155: Keep composer catalogs cached when starting a new chat.
24
+ - c0359ca: Strip a trailing slash from the `base_url` passed to agent code-snippets.
25
+ - 57f1fc2: Improve compact agent building with model configuration bottom sheets, provider-first model selection, and a contextual composer actions menu.
26
+ - e3973a5: Show the selected connector and skill count beside the composer tools icon.
27
+ - 26a9b80: Hide model selection in the Build Agent composer and correct concurrent sub-agent timeline bars.
28
+ - 26a9b80: Require direct switch clicks in the Runtime Config sidebar.
29
+ - 1ec19f0: Replace API key replacement with connector configuration editing from the connector list and details view.
30
+ - b482cdd: Show the four primary agent metrics in a compact summary-card layout.
31
+ - b32d2be: Filter chat history to sessions created by the current user, and bump `@truefoundry/assistant-ui-runtime` to `0.1.34`.
32
+ - a9430bd: Accept optional `base_url` on agent code-snippets (FE public host); fall back to request origin + `PUBLIC_BASE_URL` path.
33
+ - 54e4ec4: Keep Settings hidden until the server explicitly enables it.
34
+ - 4c522e2: Hide session cost metrics when cost data is unavailable.
35
+ - 4e7b67a: Check live per-user MCP authentication before loading tools in the agent builder.
36
+ - d2fdfc9: Section MCP tools in the Build Agent selector by read-only, others, and destructive annotations, with a read-only enable-all toggle.
37
+ - 26a9b80: Show agent names without an icon in the Agents table.
38
+ - 4cea38c: Show draft and named sessions in the history panel, exclude agent-builder sessions, cache session pages, and switch history sessions in place without remounting the chat runtime.
39
+ - 2284d3b: Polish the MCP tool selector controls, loading state, and API error messages.
40
+ - e3973a5: Group schedule recurrence controls and display the cadence in an attached summary footer.
41
+ - f2ca338: Show active/paused schedule counts in the Agents library, pin selected MCPs when reopening the tools modal, and align paused schedule badge colors.
42
+ - 77c5c33: Show TrueFoundry skill repositories and versions in skill pickers, load version choices lazily, preserve the chosen version FQN when attaching skills, keep picker ordering stable while open, and add registry-only preload controls to selected skill pills.
43
+ - 26a9b80: Show weekly schedule days before the time controls.
44
+ - 1b8a3f7: Match the Build Agent configuration panel width to the agent playground and identify sessions created by schedule runs.
45
+ - adaf532: Widen the sidebar rail and its nav buttons so labels like "Build Agent" have more breathing room.
46
+ - Updated dependencies [648273b]
47
+ - Updated dependencies [648273b]
48
+ - Updated dependencies [648273b]
49
+ - Updated dependencies [74eae6c]
50
+ - Updated dependencies [44f9cbe]
51
+ - @truefoundry/trueforge-sdk@0.2.0-rc.3
52
+
3
53
  ## 0.3.0-rc.2
4
54
 
5
55
  ### Minor Changes
package/README.md CHANGED
@@ -407,7 +407,7 @@ show the title text (see [Custom layouts](#custom-layouts)).
407
407
 
408
408
  In library modes, picking an agent from Agents switches to a named chat for that agent **and remounts the runtime** so the new agent starts from a clean conversation. Draft chats can be promoted via **Save agent** (`server.saveAgent` on the resolved `AgentUIServer`). **Clear Chat** (thread header) resets the current named or draft session.
409
409
 
410
- Mutable composers expose **Agent Config** for live model parameters, instructions, runtime behavior, per-connector MCP tools, and skills. The compact Tools picker contains only Connectors and Skills. The Save Agent dialog keeps a local editable copy of the same configuration and shares the same selector dialogs; cancelling it leaves the active draft unchanged. Model context and output limits render when the server supplies that optional catalog metadata.
410
+ Mutable composers expose **Agent Config** for live model parameters, instructions, runtime behavior, per-connector MCP tools, and skills. Runtime Config opens in a second right-side drawer. The compact Tools picker contains only Connectors and Skills. The Save Agent drawer only edits the agent name while preserving the active draft configuration; cancelling it discards that local edit. Model context and output limits render when the server supplies that optional catalog metadata.
411
411
 
412
412
  ```tsx
413
413
  {
@@ -446,12 +446,12 @@ Mutable composers expose **Agent Config** for live model parameters, instruction
446
446
 
447
447
  Built-in `layout` values:
448
448
 
449
- | Value | Description |
450
- | --------- | -------------------------------------------------------- |
451
- | `sidebar` | Left session list + main thread (ChatGPT / Claude style) |
452
- | `drawer` | Full-bleed thread; sessions open in a slide-over |
453
- | `dock` | Fixed-width right panel; list XOR thread stack |
454
- | `widget` | Same stack as `dock`, opened from a bottom-right FAB |
449
+ | Value | Description |
450
+ | --------- | ---------------------------------------------------- |
451
+ | `sidebar` | Icon rail + recent session history + active thread |
452
+ | `drawer` | Full-bleed thread; sessions open in a slide-over |
453
+ | `dock` | Fixed-width right panel; list XOR thread stack |
454
+ | `widget` | Same stack as `dock`, opened from a bottom-right FAB |
455
455
 
456
456
  ---
457
457
 
@@ -535,6 +535,7 @@ type TrueForgeServerConfig =
535
535
  apiKey: string;
536
536
  controlPlaneURL: string;
537
537
  gatewayPlaneURL?: string;
538
+ permissions?: PermissionsServer;
538
539
  }
539
540
  | {
540
541
  type: 'trueforge';
@@ -542,6 +543,7 @@ type TrueForgeServerConfig =
542
543
  token?: string;
543
544
  fetch?: typeof fetch;
544
545
  catalog?: CatalogServer;
546
+ permissions?: PermissionsServer;
545
547
  }
546
548
  | AgentUIServer;
547
549
 
@@ -551,6 +553,7 @@ type AgentUIServer = AgentChatServer &
551
553
  sessions?: AgentSessionsServer;
552
554
  metrics?: AgentMetricsServer;
553
555
  schedules?: ScheduleServer;
556
+ permissions?: PermissionsServer;
554
557
  };
555
558
  ```
556
559
 
@@ -562,9 +565,14 @@ type AgentUIServer = AgentChatServer &
562
565
  | `sessions` | Agent details + sessions browser (`/sessions`, `/library/:agentId`) |
563
566
  | `schedules` | Schedules page (`/schedules`) |
564
567
  | `AgentMetricsServer` | Agent meter aggregates, chart definitions, and chart data |
568
+ | `PermissionsServer` | Per-resource `USE`, `MANAGE`, and `DELETE` grants |
565
569
 
566
- Omit an optional port to hide its chrome and unregister its routes (same gate as the
567
- Settings button for `catalog`).
570
+ Omit a chrome port such as `catalog` or `schedules` to hide and unregister its routes.
571
+
572
+ When `permissions` is omitted from a custom or TrueFoundry server, actions remain enabled for backward compatibility.
573
+ When provided, denied mutation controls stay visible but disabled with an explanatory tooltip. The built-in
574
+ `type: "trueforge"` server enables checks automatically through the Harness permissions endpoint; an explicit
575
+ `PermissionsServer` overrides that default.
568
576
 
569
577
  **Zero-config TrueFoundry** — see [Getting started](#getting-started). The SDK calls `createTrueFoundryAgentUIServer` for you.
570
578
 
@@ -1,17 +1,17 @@
1
1
  "use client";
2
2
  import {
3
3
  useSlot
4
- } from "./chunk-YQO2NMJ3.js";
5
- import "./chunk-NHHSZB5N.js";
4
+ } from "./chunk-2O5EJ6QS.js";
5
+ import "./chunk-KR7WYHVF.js";
6
6
  import {
7
7
  Icon
8
- } from "./chunk-H6WTY5PM.js";
9
- import "./chunk-FQK2XVVE.js";
8
+ } from "./chunk-Q6TCT7ZJ.js";
9
+ import "./chunk-PT4EENB3.js";
10
10
  import "./chunk-M6MHLVSO.js";
11
- import "./chunk-VJ7BZGAF.js";
11
+ import "./chunk-J5BPHEDT.js";
12
12
  import {
13
13
  cn
14
- } from "./chunk-BWHOZFIV.js";
14
+ } from "./chunk-LXJMINS6.js";
15
15
 
16
16
  // src/atoms/agent-details/AgentCodeSnippets.tsx
17
17
  import { useEffect, useState } from "react";
@@ -48,22 +48,37 @@ function AgentCodeSnippets({ snippets }) {
48
48
  snippet.language
49
49
  )) }),
50
50
  /* @__PURE__ */ jsxs("section", { className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-lg border border-border bg-card-bg", children: [
51
- /* @__PURE__ */ jsx("div", { className: "flex h-10 shrink-0 items-end gap-1 border-b border-border px-3", children: [
52
- ["stream", "Stream"],
53
- ["nonStream", "Non-stream"]
54
- ].map(([id, label]) => /* @__PURE__ */ jsx(
55
- "button",
56
- {
57
- type: "button",
58
- className: cn(
59
- "relative h-10 cursor-pointer px-3 text-xs font-medium text-text-secondary",
60
- mode === id && "text-primary-button-bg after:absolute after:inset-x-0 after:bottom-0 after:h-0.5 after:bg-primary-button-bg"
61
- ),
62
- onClick: () => setMode(id),
63
- children: label
64
- },
65
- id
66
- )) }),
51
+ /* @__PURE__ */ jsxs("div", { className: "flex h-10 shrink-0 items-center justify-between gap-1 border-b border-border px-3", children: [
52
+ /* @__PURE__ */ jsx("div", { className: "flex items-end gap-1", children: [
53
+ ["stream", "Stream"],
54
+ ["nonStream", "Non-stream"]
55
+ ].map(([id, label]) => /* @__PURE__ */ jsx(
56
+ "button",
57
+ {
58
+ type: "button",
59
+ className: cn(
60
+ "relative h-10 cursor-pointer px-3 text-xs font-medium text-text-secondary",
61
+ mode === id && "text-primary-button-bg after:absolute after:inset-x-0 after:bottom-0 after:h-0.5 after:bg-primary-button-bg"
62
+ ),
63
+ onClick: () => setMode(id),
64
+ children: label
65
+ },
66
+ id
67
+ )) }),
68
+ /* @__PURE__ */ jsxs(
69
+ "a",
70
+ {
71
+ href: "https://trueforge.dev/api/use-agent",
72
+ target: "_blank",
73
+ rel: "noopener noreferrer",
74
+ className: "flex items-center gap-1 text-xs text-text-secondary",
75
+ children: [
76
+ /* @__PURE__ */ jsx("span", { children: "View Docs" }),
77
+ /* @__PURE__ */ jsx(Icon, { name: "external-link", className: "size-3 shrink-0" })
78
+ ]
79
+ }
80
+ )
81
+ ] }),
67
82
  /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto", children: /* @__PURE__ */ jsx(AgentCodeBlock, { code: selected.sampleCode[mode], language: selected.language }) })
68
83
  ] })
69
84
  ] });
@@ -71,4 +86,4 @@ function AgentCodeSnippets({ snippets }) {
71
86
  export {
72
87
  AgentCodeSnippets as default
73
88
  };
74
- //# sourceMappingURL=AgentCodeSnippets-637HQUXD.js.map
89
+ //# sourceMappingURL=AgentCodeSnippets-N546FNNS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/atoms/agent-details/AgentCodeSnippets.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useState, type ComponentType } from 'react';\nimport { Icon } from '../../icons/Icon.js';\nimport { useSlot } from '../../theme/SlotsProvider.js';\nimport { cn } from '../lib/cn.js';\nimport type { AgentCodeSnippetsProps } from './types.js';\n\ntype SnippetMode = 'stream' | 'nonStream';\n\nexport default function AgentCodeSnippets({ snippets }: AgentCodeSnippetsProps) {\n const AgentCodeBlock = useSlot('AgentCodeBlock');\n const [selectedLanguage, setSelectedLanguage] = useState(snippets[0]?.language);\n const [mode, setMode] = useState<SnippetMode>('stream');\n\n useEffect(() => {\n setSelectedLanguage(snippets[0]?.language);\n setMode('stream');\n }, [snippets]);\n\n const selected = snippets.find(snippet => snippet.language === selectedLanguage) ?? snippets[0];\n\n if (selected === undefined) {\n return (\n <div className=\"flex h-full min-h-64 items-center justify-center px-6 text-sm text-text-secondary\">\n No code samples for this agent.\n </div>\n );\n }\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col gap-3 p-3 md:flex-row\">\n <nav aria-label=\"Code sample languages\" className=\"flex shrink-0 gap-1 overflow-auto md:w-44 md:flex-col\">\n {snippets.map(snippet => (\n <button\n key={snippet.language}\n type=\"button\"\n aria-current={selected.language === snippet.language ? 'page' : undefined}\n className={cn(\n 'flex h-9 shrink-0 cursor-pointer items-center gap-2 rounded-md px-2.5 text-left text-xs text-text-secondary',\n 'hover:bg-ghost-button-hover hover:text-text-primary',\n selected.language === snippet.language && 'bg-primary-button-bg/10 font-medium text-primary-button-bg',\n )}\n onClick={() => setSelectedLanguage(snippet.language)}\n >\n {snippet.icon ? (\n <img src={snippet.icon} alt=\"\" className=\"size-4 shrink-0 object-contain\" />\n ) : (\n <Icon name=\"code\" className=\"size-4 shrink-0\" />\n )}\n {snippet.labelName}\n </button>\n ))}\n </nav>\n\n <section className=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-lg border border-border bg-card-bg\">\n <div className=\"flex h-10 shrink-0 items-center justify-between gap-1 border-b border-border px-3\">\n <div className=\"flex items-end gap-1\">\n {(\n [\n ['stream', 'Stream'],\n ['nonStream', 'Non-stream'],\n ] satisfies Array<[SnippetMode, string]>\n ).map(([id, label]) => (\n <button\n key={id}\n type=\"button\"\n className={cn(\n 'relative h-10 cursor-pointer px-3 text-xs font-medium text-text-secondary',\n mode === id &&\n 'text-primary-button-bg after:absolute after:inset-x-0 after:bottom-0 after:h-0.5 after:bg-primary-button-bg',\n )}\n onClick={() => setMode(id)}\n >\n {label}\n </button>\n ))}\n </div>\n <a\n href=\"https://trueforge.dev/api/use-agent\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center gap-1 text-xs text-text-secondary\"\n >\n <span>View Docs</span>\n <Icon name=\"external-link\" className=\"size-3 shrink-0\" />\n </a>\n </div>\n <div className=\"min-h-0 flex-1 overflow-auto\">\n <AgentCodeBlock code={selected.sampleCode[mode]} language={selected.language} />\n </div>\n </section>\n </div>\n );\n}\n\ndeclare module '../../theme/SlotsProvider.js' {\n interface AtomSlots {\n AgentCodeSnippets: ComponentType<AgentCodeSnippetsProps>;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAEA,SAAS,WAAW,gBAAoC;AAsBlD,cAUI,YAVJ;AAdS,SAAR,kBAAmC,EAAE,SAAS,GAA2B;AAC9E,QAAM,iBAAiB,QAAQ,gBAAgB;AAC/C,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,SAAS,SAAS,CAAC,GAAG,QAAQ;AAC9E,QAAM,CAAC,MAAM,OAAO,IAAI,SAAsB,QAAQ;AAEtD,YAAU,MAAM;AACd,wBAAoB,SAAS,CAAC,GAAG,QAAQ;AACzC,YAAQ,QAAQ;AAAA,EAClB,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,WAAW,SAAS,KAAK,aAAW,QAAQ,aAAa,gBAAgB,KAAK,SAAS,CAAC;AAE9F,MAAI,aAAa,QAAW;AAC1B,WACE,oBAAC,SAAI,WAAU,qFAAoF,6CAEnG;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAU,sDACb;AAAA,wBAAC,SAAI,cAAW,yBAAwB,WAAU,yDAC/C,mBAAS,IAAI,aACZ;AAAA,MAAC;AAAA;AAAA,QAEC,MAAK;AAAA,QACL,gBAAc,SAAS,aAAa,QAAQ,WAAW,SAAS;AAAA,QAChE,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,SAAS,aAAa,QAAQ,YAAY;AAAA,QAC5C;AAAA,QACA,SAAS,MAAM,oBAAoB,QAAQ,QAAQ;AAAA,QAElD;AAAA,kBAAQ,OACP,oBAAC,SAAI,KAAK,QAAQ,MAAM,KAAI,IAAG,WAAU,kCAAiC,IAE1E,oBAAC,QAAK,MAAK,QAAO,WAAU,mBAAkB;AAAA,UAE/C,QAAQ;AAAA;AAAA;AAAA,MAfJ,QAAQ;AAAA,IAgBf,CACD,GACH;AAAA,IAEA,qBAAC,aAAQ,WAAU,mGACjB;AAAA,2BAAC,SAAI,WAAU,qFACb;AAAA,4BAAC,SAAI,WAAU,wBAEX;AAAA,UACE,CAAC,UAAU,QAAQ;AAAA,UACnB,CAAC,aAAa,YAAY;AAAA,QAC5B,EACA,IAAI,CAAC,CAAC,IAAI,KAAK,MACf;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,WAAW;AAAA,cACT;AAAA,cACA,SAAS,MACP;AAAA,YACJ;AAAA,YACA,SAAS,MAAM,QAAQ,EAAE;AAAA,YAExB;AAAA;AAAA,UATI;AAAA,QAUP,CACD,GACH;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,QAAO;AAAA,YACP,KAAI;AAAA,YACJ,WAAU;AAAA,YAEV;AAAA,kCAAC,UAAK,uBAAS;AAAA,cACf,oBAAC,QAAK,MAAK,iBAAgB,WAAU,mBAAkB;AAAA;AAAA;AAAA,QACzD;AAAA,SACF;AAAA,MACA,oBAAC,SAAI,WAAU,gCACb,8BAAC,kBAAe,MAAM,SAAS,WAAW,IAAI,GAAG,UAAU,SAAS,UAAU,GAChF;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import {
3
+ AgentMetricChart
4
+ } from "./chunk-XLFOXQKZ.js";
5
+ import "./chunk-2O5EJ6QS.js";
6
+ import "./chunk-KR7WYHVF.js";
7
+ import "./chunk-Q6TCT7ZJ.js";
8
+ import "./chunk-PT4EENB3.js";
9
+ import "./chunk-M6MHLVSO.js";
10
+ import "./chunk-J5BPHEDT.js";
11
+ import "./chunk-LXJMINS6.js";
12
+ export {
13
+ AgentMetricChart
14
+ };
15
+ //# sourceMappingURL=AgentMetricChart-YWJYVYYA.js.map
@@ -1,17 +1,17 @@
1
1
  "use client";
2
2
  import {
3
3
  useSlot
4
- } from "./chunk-YQO2NMJ3.js";
5
- import "./chunk-NHHSZB5N.js";
4
+ } from "./chunk-2O5EJ6QS.js";
5
+ import "./chunk-KR7WYHVF.js";
6
6
  import {
7
7
  Icon
8
- } from "./chunk-H6WTY5PM.js";
9
- import "./chunk-FQK2XVVE.js";
8
+ } from "./chunk-Q6TCT7ZJ.js";
9
+ import "./chunk-PT4EENB3.js";
10
10
  import "./chunk-M6MHLVSO.js";
11
- import "./chunk-VJ7BZGAF.js";
11
+ import "./chunk-J5BPHEDT.js";
12
12
  import {
13
13
  cn
14
- } from "./chunk-BWHOZFIV.js";
14
+ } from "./chunk-LXJMINS6.js";
15
15
 
16
16
  // src/atoms/agent-details/AgentOverview.tsx
17
17
  import { useState } from "react";
@@ -164,4 +164,4 @@ function AgentOverview({ detail }) {
164
164
  export {
165
165
  AgentOverview as default
166
166
  };
167
- //# sourceMappingURL=AgentOverview-3FJ5EE6N.js.map
167
+ //# sourceMappingURL=AgentOverview-VF74XC7I.js.map
@@ -4,15 +4,15 @@ import {
4
4
  getSessionEventColor,
5
5
  useSlot,
6
6
  useThemeMode
7
- } from "./chunk-YQO2NMJ3.js";
8
- import "./chunk-NHHSZB5N.js";
9
- import "./chunk-H6WTY5PM.js";
10
- import "./chunk-FQK2XVVE.js";
7
+ } from "./chunk-2O5EJ6QS.js";
8
+ import "./chunk-KR7WYHVF.js";
9
+ import "./chunk-Q6TCT7ZJ.js";
10
+ import "./chunk-PT4EENB3.js";
11
11
  import "./chunk-M6MHLVSO.js";
12
- import "./chunk-VJ7BZGAF.js";
12
+ import "./chunk-J5BPHEDT.js";
13
13
  import {
14
14
  cn
15
- } from "./chunk-BWHOZFIV.js";
15
+ } from "./chunk-LXJMINS6.js";
16
16
 
17
17
  // src/atoms/agent-details/AgentSessionEventTimeline.tsx
18
18
  import { useCallback, useMemo, useState } from "react";
@@ -71,7 +71,7 @@ function AgentSessionEventTimeline({ turns, segments, onSelectTurn }) {
71
71
  ]
72
72
  }
73
73
  ),
74
- /* @__PURE__ */ jsx("div", { className: "w-full py-2", children: /* @__PURE__ */ jsx(
74
+ /* @__PURE__ */ jsx("div", { className: "w-full p-2", children: /* @__PURE__ */ jsx(
75
75
  AgentSessionEventTimelineChart,
76
76
  {
77
77
  turns,
@@ -85,4 +85,4 @@ function AgentSessionEventTimeline({ turns, segments, onSelectTurn }) {
85
85
  export {
86
86
  AgentSessionEventTimeline
87
87
  };
88
- //# sourceMappingURL=AgentSessionEventTimeline-VELWUYPR.js.map
88
+ //# sourceMappingURL=AgentSessionEventTimeline-RFR6LQMY.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/atoms/agent-details/AgentSessionEventTimeline.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useMemo, useState, type ComponentType } from 'react';\n\nimport { useSlot, useThemeMode } from '../../theme/SlotsProvider.js';\nimport { getSessionEventColor, SESSION_EVENT_TYPES, type SessionEventType } from '../../utils/sessionEventTimeline.js';\nimport { cn } from '../lib/cn.js';\nimport type { AgentSessionEventTimelineProps } from './types.js';\n\nexport function AgentSessionEventTimeline({ turns, segments, onSelectTurn }: AgentSessionEventTimelineProps) {\n const AgentSessionEventTimelineChart = useSlot('AgentSessionEventTimelineChart');\n const isDark = useThemeMode() === 'dark';\n const [hiddenTypes, setHiddenTypes] = useState<Set<SessionEventType>>(() => new Set());\n\n const availableEventTypes = useMemo(() => {\n const available = new Set(segments.map(segment => segment.type));\n return SESSION_EVENT_TYPES.filter(eventType => available.has(eventType.id));\n }, [segments]);\n\n const handleToggleType = useCallback((type: SessionEventType) => {\n setHiddenTypes(previous => {\n const next = new Set(previous);\n if (next.has(type)) next.delete(type);\n else next.add(type);\n return next;\n });\n }, []);\n\n if (segments.length === 0) return null;\n\n return (\n <div className=\"w-full\" data-slot=\"agent-session-event-timeline\">\n <div\n className=\"flex flex-wrap items-center gap-2 border-b border-border px-3 py-2\"\n data-slot=\"agent-session-event-types\"\n >\n <span className=\"text-xs font-medium uppercase text-text-secondary\">Event types</span>\n <div className=\"flex flex-wrap items-center gap-1\">\n {availableEventTypes.map(eventType => {\n const isVisible = !hiddenTypes.has(eventType.id);\n return (\n <button\n key={eventType.id}\n type=\"button\"\n aria-pressed={isVisible}\n className={cn(\n 'flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs font-medium',\n isVisible ? 'border-border text-text-primary' : 'border-transparent text-text-secondary opacity-80',\n )}\n onClick={() => handleToggleType(eventType.id)}\n >\n <span\n className=\"size-2 rounded-sm\"\n style={{ backgroundColor: getSessionEventColor(eventType.id, isDark) }}\n />\n {eventType.label}\n </button>\n );\n })}\n </div>\n </div>\n <div className=\"w-full py-2\">\n <AgentSessionEventTimelineChart\n turns={turns}\n segments={segments}\n hiddenTypes={hiddenTypes}\n onSelectTurn={onSelectTurn}\n />\n </div>\n </div>\n );\n}\n\ndeclare module '../../theme/SlotsProvider.js' {\n interface AtomSlots {\n AgentSessionEventTimeline: ComponentType<AgentSessionEventTimelineProps>;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAEA,SAAS,aAAa,SAAS,gBAAoC;AAkC3D,cAKM,YALN;AA3BD,SAAS,0BAA0B,EAAE,OAAO,UAAU,aAAa,GAAmC;AAC3G,QAAM,iCAAiC,QAAQ,gCAAgC;AAC/E,QAAM,SAAS,aAAa,MAAM;AAClC,QAAM,CAAC,aAAa,cAAc,IAAI,SAAgC,MAAM,oBAAI,IAAI,CAAC;AAErF,QAAM,sBAAsB,QAAQ,MAAM;AACxC,UAAM,YAAY,IAAI,IAAI,SAAS,IAAI,aAAW,QAAQ,IAAI,CAAC;AAC/D,WAAO,oBAAoB,OAAO,eAAa,UAAU,IAAI,UAAU,EAAE,CAAC;AAAA,EAC5E,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,mBAAmB,YAAY,CAAC,SAA2B;AAC/D,mBAAe,cAAY;AACzB,YAAM,OAAO,IAAI,IAAI,QAAQ;AAC7B,UAAI,KAAK,IAAI,IAAI,EAAG,MAAK,OAAO,IAAI;AAAA,UAC/B,MAAK,IAAI,IAAI;AAClB,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,SACE,qBAAC,SAAI,WAAU,UAAS,aAAU,gCAChC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,aAAU;AAAA,QAEV;AAAA,8BAAC,UAAK,WAAU,qDAAoD,yBAAW;AAAA,UAC/E,oBAAC,SAAI,WAAU,qCACZ,8BAAoB,IAAI,eAAa;AACpC,kBAAM,YAAY,CAAC,YAAY,IAAI,UAAU,EAAE;AAC/C,mBACE;AAAA,cAAC;AAAA;AAAA,gBAEC,MAAK;AAAA,gBACL,gBAAc;AAAA,gBACd,WAAW;AAAA,kBACT;AAAA,kBACA,YAAY,oCAAoC;AAAA,gBAClD;AAAA,gBACA,SAAS,MAAM,iBAAiB,UAAU,EAAE;AAAA,gBAE5C;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAU;AAAA,sBACV,OAAO,EAAE,iBAAiB,qBAAqB,UAAU,IAAI,MAAM,EAAE;AAAA;AAAA,kBACvE;AAAA,kBACC,UAAU;AAAA;AAAA;AAAA,cAbN,UAAU;AAAA,YAcjB;AAAA,UAEJ,CAAC,GACH;AAAA;AAAA;AAAA,IACF;AAAA,IACA,oBAAC,SAAI,WAAU,eACb;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/atoms/agent-details/AgentSessionEventTimeline.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useMemo, useState, type ComponentType } from 'react';\n\nimport { useSlot, useThemeMode } from '../../theme/SlotsProvider.js';\nimport { getSessionEventColor, SESSION_EVENT_TYPES, type SessionEventType } from '../../utils/sessionEventTimeline.js';\nimport { cn } from '../lib/cn.js';\nimport type { AgentSessionEventTimelineProps } from './types.js';\n\nexport function AgentSessionEventTimeline({ turns, segments, onSelectTurn }: AgentSessionEventTimelineProps) {\n const AgentSessionEventTimelineChart = useSlot('AgentSessionEventTimelineChart');\n const isDark = useThemeMode() === 'dark';\n const [hiddenTypes, setHiddenTypes] = useState<Set<SessionEventType>>(() => new Set());\n\n const availableEventTypes = useMemo(() => {\n const available = new Set(segments.map(segment => segment.type));\n return SESSION_EVENT_TYPES.filter(eventType => available.has(eventType.id));\n }, [segments]);\n\n const handleToggleType = useCallback((type: SessionEventType) => {\n setHiddenTypes(previous => {\n const next = new Set(previous);\n if (next.has(type)) next.delete(type);\n else next.add(type);\n return next;\n });\n }, []);\n\n if (segments.length === 0) return null;\n\n return (\n <div className=\"w-full\" data-slot=\"agent-session-event-timeline\">\n <div\n className=\"flex flex-wrap items-center gap-2 border-b border-border px-3 py-2\"\n data-slot=\"agent-session-event-types\"\n >\n <span className=\"text-xs font-medium uppercase text-text-secondary\">Event types</span>\n <div className=\"flex flex-wrap items-center gap-1\">\n {availableEventTypes.map(eventType => {\n const isVisible = !hiddenTypes.has(eventType.id);\n return (\n <button\n key={eventType.id}\n type=\"button\"\n aria-pressed={isVisible}\n className={cn(\n 'flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs font-medium',\n isVisible ? 'border-border text-text-primary' : 'border-transparent text-text-secondary opacity-80',\n )}\n onClick={() => handleToggleType(eventType.id)}\n >\n <span\n className=\"size-2 rounded-sm\"\n style={{ backgroundColor: getSessionEventColor(eventType.id, isDark) }}\n />\n {eventType.label}\n </button>\n );\n })}\n </div>\n </div>\n <div className=\"w-full p-2\">\n <AgentSessionEventTimelineChart\n turns={turns}\n segments={segments}\n hiddenTypes={hiddenTypes}\n onSelectTurn={onSelectTurn}\n />\n </div>\n </div>\n );\n}\n\ndeclare module '../../theme/SlotsProvider.js' {\n interface AtomSlots {\n AgentSessionEventTimeline: ComponentType<AgentSessionEventTimelineProps>;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAEA,SAAS,aAAa,SAAS,gBAAoC;AAkC3D,cAKM,YALN;AA3BD,SAAS,0BAA0B,EAAE,OAAO,UAAU,aAAa,GAAmC;AAC3G,QAAM,iCAAiC,QAAQ,gCAAgC;AAC/E,QAAM,SAAS,aAAa,MAAM;AAClC,QAAM,CAAC,aAAa,cAAc,IAAI,SAAgC,MAAM,oBAAI,IAAI,CAAC;AAErF,QAAM,sBAAsB,QAAQ,MAAM;AACxC,UAAM,YAAY,IAAI,IAAI,SAAS,IAAI,aAAW,QAAQ,IAAI,CAAC;AAC/D,WAAO,oBAAoB,OAAO,eAAa,UAAU,IAAI,UAAU,EAAE,CAAC;AAAA,EAC5E,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,mBAAmB,YAAY,CAAC,SAA2B;AAC/D,mBAAe,cAAY;AACzB,YAAM,OAAO,IAAI,IAAI,QAAQ;AAC7B,UAAI,KAAK,IAAI,IAAI,EAAG,MAAK,OAAO,IAAI;AAAA,UAC/B,MAAK,IAAI,IAAI;AAClB,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,SACE,qBAAC,SAAI,WAAU,UAAS,aAAU,gCAChC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,aAAU;AAAA,QAEV;AAAA,8BAAC,UAAK,WAAU,qDAAoD,yBAAW;AAAA,UAC/E,oBAAC,SAAI,WAAU,qCACZ,8BAAoB,IAAI,eAAa;AACpC,kBAAM,YAAY,CAAC,YAAY,IAAI,UAAU,EAAE;AAC/C,mBACE;AAAA,cAAC;AAAA;AAAA,gBAEC,MAAK;AAAA,gBACL,gBAAc;AAAA,gBACd,WAAW;AAAA,kBACT;AAAA,kBACA,YAAY,oCAAoC;AAAA,gBAClD;AAAA,gBACA,SAAS,MAAM,iBAAiB,UAAU,EAAE;AAAA,gBAE5C;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAU;AAAA,sBACV,OAAO,EAAE,iBAAiB,qBAAqB,UAAU,IAAI,MAAM,EAAE;AAAA;AAAA,kBACvE;AAAA,kBACC,UAAU;AAAA;AAAA;AAAA,cAbN,UAAU;AAAA,YAcjB;AAAA,UAEJ,CAAC,GACH;AAAA;AAAA;AAAA,IACF;AAAA,IACA,oBAAC,SAAI,WAAU,cACb;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;","names":[]}
@@ -22,16 +22,16 @@ import {
22
22
  getTimelineRange,
23
23
  groupCoincidentTimelineMarkers,
24
24
  groupOverlappingToolCalls,
25
- pickLongestNonOverlappingSegments,
25
+ mergeOverlappingSubAgentSegments,
26
26
  roundDurationMsToSecond,
27
27
  useThemeMode
28
- } from "./chunk-YQO2NMJ3.js";
29
- import "./chunk-NHHSZB5N.js";
30
- import "./chunk-H6WTY5PM.js";
31
- import "./chunk-FQK2XVVE.js";
28
+ } from "./chunk-2O5EJ6QS.js";
29
+ import "./chunk-KR7WYHVF.js";
30
+ import "./chunk-Q6TCT7ZJ.js";
31
+ import "./chunk-PT4EENB3.js";
32
32
  import "./chunk-M6MHLVSO.js";
33
- import "./chunk-VJ7BZGAF.js";
34
- import "./chunk-BWHOZFIV.js";
33
+ import "./chunk-J5BPHEDT.js";
34
+ import "./chunk-LXJMINS6.js";
35
35
 
36
36
  // src/atoms/agent-details/AgentSessionEventTimelineChart.tsx
37
37
  import {
@@ -269,7 +269,7 @@ function AgentSessionEventTimelineChart({
269
269
  () => durationSegments.filter((segment) => segment.type === "sub_agent"),
270
270
  [durationSegments]
271
271
  );
272
- const mainSubAgents = useMemo(() => pickLongestNonOverlappingSegments(subAgentSegments), [subAgentSegments]);
272
+ const mainSubAgents = useMemo(() => mergeOverlappingSubAgentSegments(subAgentSegments), [subAgentSegments]);
273
273
  const subAgentGroups = useMemo(
274
274
  () => getSubAgentHoverGroups({ bars: mainSubAgents, subAgentSegments }),
275
275
  [mainSubAgents, subAgentSegments]
@@ -279,9 +279,8 @@ function AgentSessionEventTimelineChart({
279
279
  [durationSegments, msPerPx, subAgentSegments]
280
280
  );
281
281
  const mainCandidates = useMemo(() => {
282
- const kept = new Set(mainSubAgents.map((segment) => segment.id));
283
- return durationSegments.filter(
284
- (segment) => segment.threadId === MAIN_THREAD_ID || segment.type === "sub_agent" && kept.has(segment.id)
282
+ return [...durationSegments.filter((segment) => segment.threadId === MAIN_THREAD_ID), ...mainSubAgents].sort(
283
+ (left, right) => left.startMs - right.startMs || left.endMs - right.endMs
285
284
  );
286
285
  }, [durationSegments, mainSubAgents]);
287
286
  const toolCallGroups = useMemo(
@@ -511,6 +510,7 @@ function AgentSessionEventTimelineChart({
511
510
  },
512
511
  ticks: {
513
512
  color: axis,
513
+ align: "inner",
514
514
  autoSkip: false,
515
515
  includeBounds: false,
516
516
  maxTicksLimit: 9,
@@ -588,4 +588,4 @@ function AgentSessionEventTimelineChart({
588
588
  export {
589
589
  AgentSessionEventTimelineChart
590
590
  };
591
- //# sourceMappingURL=AgentSessionEventTimelineChart-CUKETHWM.js.map
591
+ //# sourceMappingURL=AgentSessionEventTimelineChart-27CQF6FX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/atoms/agent-details/AgentSessionEventTimelineChart.tsx","../src/atoms/agent-details/AgentSessionTimelineTooltip.tsx"],"sourcesContent":["'use client';\n\nimport {\n BarController,\n BarElement,\n Chart as ChartJS,\n LinearScale,\n PointElement,\n ScatterController,\n Tooltip,\n type ChartData,\n type ChartDataset,\n type ChartOptions,\n type Plugin,\n} from 'chart.js';\nimport { useCallback, useEffect, useMemo, useRef, useState, type ComponentType, type CSSProperties } from 'react';\nimport { Chart } from 'react-chartjs-2';\n\nimport { useThemeMode } from '../../theme/SlotsProvider.js';\nimport { roundDurationMsToSecond } from '../../utils/sessionDisplayFormat.js';\nimport {\n getSessionEventColor,\n getSessionEventHoverColor,\n getSessionEventLabel,\n MAIN_THREAD_ID,\n type SessionEventTimelineSegment,\n} from '../../utils/sessionEventTimeline.js';\nimport {\n buildTimelineAxisTicks,\n formatTimelineAxisDuration,\n getActiveTimelineMs,\n getSubAgentHoverGroups,\n getSubAgentLanes,\n getTimelineHoverTargetId,\n getTimelineLayout,\n getTimelineRange,\n groupCoincidentTimelineMarkers,\n groupOverlappingToolCalls,\n mergeOverlappingSubAgentSegments,\n TIMELINE_TYPE,\n type TimelineGap,\n type TimelineHoverTarget,\n type TimelineTurnBar,\n} from '../../utils/sessionEventTimelineChart.js';\nimport { LightTooltip } from '../primitives/Tooltip.js';\nimport {\n hasSessionEventTooltip,\n SessionEventTooltip,\n SessionMarkerGroupTooltip,\n SessionSubAgentGroupTooltip,\n SessionToolCallGroupTooltip,\n SessionTurnTooltip,\n} from './AgentSessionTimelineTooltip.js';\nimport type { AgentSessionEventTimelineChartProps } from './types.js';\n\nChartJS.register(BarController, BarElement, LinearScale, PointElement, ScatterController, Tooltip);\n\nconst MARKER_PX = 4;\nconst TURN_GAP_PX = 12;\nconst END_PAD_PX = 12;\nconst BAR_RADIUS_PX = 2;\nconst ROW_GAP_PX = 8;\nconst MARKER_EVENT_GAP_PX = 2;\nconst OVERHEAD_PX = 30;\n\ntype BarPoint = { x: [number, number]; y: number };\ntype MarkerPoint = { x: number; y: number };\ntype TimelineChartType = 'bar' | 'scatter';\n\nfunction rowCenters({ heights, gaps }: { heights: number[]; gaps: number[] }): { centers: number[]; band: number } {\n const centers: number[] = [];\n let offset = 0;\n heights.forEach((height, index) => {\n centers.push(offset + height / 2);\n offset += height + (gaps[index] ?? 0);\n });\n return { centers, band: offset };\n}\n\nfunction eventOrder(type: SessionEventTimelineSegment['type']): number {\n if (type === 'sub_agent') return 0;\n if (type === 'model') return 2;\n return 1;\n}\n\nfunction turnBarLabelPoint(element: object): { x: number; y: number } | null {\n if (!('x' in element) || !('y' in element) || !('base' in element)) return null;\n const { x, y, base } = element;\n if (typeof x !== 'number' || typeof y !== 'number' || typeof base !== 'number') return null;\n return { x: (x + base) / 2, y };\n}\n\nexport function AgentSessionEventTimelineChart({\n turns,\n segments,\n hiddenTypes,\n onSelectTurn,\n}: AgentSessionEventTimelineChartProps) {\n const mode = useThemeMode();\n const isDark = mode === 'dark';\n const axis = isDark ? '#8c8c92' : '#71717a';\n const grid = isDark ? '#27272a' : '#e4e4e7';\n const turnFill = isDark ? '#3f3f46' : '#E0ECFD';\n const turnHover = isDark ? '#52525b' : '#E0ECFD';\n const wrapperRef = useRef<HTMLDivElement>(null);\n const [widthPx, setWidthPx] = useState(0);\n const [overheadPx, setOverheadPx] = useState(OVERHEAD_PX);\n const [tooltipTarget, setTooltipTarget] = useState<TimelineHoverTarget | null>(null);\n const [tooltipAnchor, setTooltipAnchor] = useState<{ left: number; top: number } | null>(null);\n const tooltipIdRef = useRef('');\n const tooltipCursorXRef = useRef<number | null>(null);\n\n useEffect(() => {\n const wrapper = wrapperRef.current;\n if (wrapper == null) return undefined;\n const update = () => setWidthPx(wrapper.clientWidth);\n update();\n const observer = new ResizeObserver(update);\n observer.observe(wrapper);\n return () => observer.disconnect();\n }, []);\n\n const refreshTooltipAnchor = useCallback(() => {\n const wrapper = wrapperRef.current;\n const left = tooltipCursorXRef.current;\n if (wrapper == null || left == null) return;\n setTooltipAnchor({ left, top: wrapper.getBoundingClientRect().bottom });\n }, []);\n\n const clearTooltip = useCallback(() => {\n tooltipIdRef.current = '';\n tooltipCursorXRef.current = null;\n setTooltipTarget(null);\n setTooltipAnchor(null);\n }, []);\n\n useEffect(() => {\n if (tooltipTarget == null) return undefined;\n // Anchors use viewport coordinates, so remeasure the chart whenever any\n // scroll ancestor or the viewport moves it.\n refreshTooltipAnchor();\n window.addEventListener('scroll', refreshTooltipAnchor, true);\n window.addEventListener('resize', refreshTooltipAnchor);\n return () => {\n window.removeEventListener('scroll', refreshTooltipAnchor, true);\n window.removeEventListener('resize', refreshTooltipAnchor);\n };\n }, [refreshTooltipAnchor, tooltipTarget]);\n\n const segmentTotalMs = Math.max(0, ...segments.map(segment => segment.endMs));\n const activeTotalMs = Math.max(1, roundDurationMsToSecond(segmentTotalMs));\n const { turnStartsMs, turnOrdinals, turnRanges } = useMemo(() => getTimelineLayout(segments), [segments]);\n const activeTurnStartsMs = useMemo(\n () => turnStartsMs.filter((startMs, index) => index === 0 || startMs <= activeTotalMs),\n [activeTotalMs, turnStartsMs],\n );\n const gapCount = Math.max(0, activeTurnStartsMs.length - 1);\n const scaleWidthPx = Math.max(widthPx / 2, widthPx - TURN_GAP_PX * gapCount - END_PAD_PX);\n const msPerPx = activeTotalMs / Math.max(1, scaleWidthPx);\n const turnGapMs = TURN_GAP_PX * msPerPx;\n const totalMs = activeTotalMs + gapCount * turnGapMs;\n const timelineMaxMs = totalMs + END_PAD_PX * msPerPx;\n const timelineGaps = useMemo<TimelineGap[]>(\n () =>\n activeTurnStartsMs\n .slice(1)\n .map((startMs, index) => ({ startMs: startMs + index * turnGapMs, endMs: startMs + (index + 1) * turnGapMs })),\n [activeTurnStartsMs, turnGapMs],\n );\n\n const visibleSegments = useMemo(\n () =>\n segments.flatMap(segment => {\n if (hiddenTypes.has(segment.type)) return [];\n const shiftMs = (turnOrdinals.get(segment.turnIndex) ?? 0) * turnGapMs;\n return [{ ...segment, startMs: segment.startMs + shiftMs, endMs: segment.endMs + shiftMs }];\n }),\n [hiddenTypes, segments, turnGapMs, turnOrdinals],\n );\n const markerGroups = useMemo(() => groupCoincidentTimelineMarkers(visibleSegments), [visibleSegments]);\n const durationSegments = useMemo(() => visibleSegments.filter(segment => !segment.isMarker), [visibleSegments]);\n const turnBars = useMemo<TimelineTurnBar[]>(\n () =>\n turnRanges.length < 2\n ? []\n : turnRanges.map(range => ({\n ...range,\n id: `turn-${range.turnIndex}`,\n durationMs: range.endMs - range.startMs,\n startMs: range.startMs + range.ordinal * turnGapMs,\n endMs: range.endMs + range.ordinal * turnGapMs + MARKER_PX * msPerPx,\n })),\n [msPerPx, turnGapMs, turnRanges],\n );\n const subAgentSegments = useMemo(\n () => durationSegments.filter(segment => segment.type === 'sub_agent'),\n [durationSegments],\n );\n const mainSubAgents = useMemo(() => mergeOverlappingSubAgentSegments(subAgentSegments), [subAgentSegments]);\n const subAgentGroups = useMemo(\n () => getSubAgentHoverGroups({ bars: mainSubAgents, subAgentSegments }),\n [mainSubAgents, subAgentSegments],\n );\n const subAgentLanes = useMemo(\n () => getSubAgentLanes({ subAgentSegments, threadSegments: durationSegments, minWidthMs: MARKER_PX * msPerPx }),\n [durationSegments, msPerPx, subAgentSegments],\n );\n const mainCandidates = useMemo(() => {\n return [...durationSegments.filter(segment => segment.threadId === MAIN_THREAD_ID), ...mainSubAgents].sort(\n (left, right) => left.startMs - right.startMs || left.endMs - right.endMs,\n );\n }, [durationSegments, mainSubAgents]);\n const toolCallGroups = useMemo(\n () =>\n groupOverlappingToolCalls(mainCandidates.filter(segment => segment.type === 'tool_call')).filter(\n group => group.segments.length > 1,\n ),\n [mainCandidates],\n );\n const groupedIds = useMemo(\n () => new Set(toolCallGroups.flatMap(group => group.segments.map(segment => segment.id))),\n [toolCallGroups],\n );\n const mainEventSegments = useMemo(\n () => mainCandidates.filter(segment => !groupedIds.has(segment.id)),\n [groupedIds, mainCandidates],\n );\n const laneCount = subAgentLanes.reduce((count, lane) => Math.max(count, lane.lane + 1), 0);\n const hasTurnRow = turnBars.length > 0;\n const markerRow = hasTurnRow ? 1 : 0;\n const eventRow = markerRow + 1;\n const { centers, band } = useMemo(() => {\n const heights = [...(hasTurnRow ? [16] : []), 10, 28, ...Array.from({ length: laneCount }, () => 12)];\n const gaps = heights.map((_, index) => {\n if (index === heights.length - 1) return 0;\n return index === markerRow ? MARKER_EVENT_GAP_PX : ROW_GAP_PX;\n });\n return rowCenters({ heights, gaps });\n }, [hasTurnRow, laneCount, markerRow]);\n\n const chartTargets = useMemo<Array<TimelineHoverTarget | null>>(\n () => [\n ...turnBars.map((bar): TimelineHoverTarget => ({ type: TIMELINE_TYPE.turn, bar })),\n ...markerGroups.map((group): TimelineHoverTarget => ({ type: TIMELINE_TYPE.markerGroup, group })),\n ...subAgentLanes.flatMap(lane =>\n lane.segments.map((segment): TimelineHoverTarget => ({ type: TIMELINE_TYPE.event, segment })),\n ),\n ...mainEventSegments.map((segment): TimelineHoverTarget | null => {\n if (segment.type !== 'sub_agent') return { type: TIMELINE_TYPE.event, segment };\n const group = subAgentGroups.find(candidate => candidate.barId === segment.id);\n return group == null ? { type: TIMELINE_TYPE.event, segment } : { type: TIMELINE_TYPE.subAgentGroup, group };\n }),\n ...toolCallGroups.map((group): TimelineHoverTarget => ({ type: TIMELINE_TYPE.toolCallGroup, group })),\n ],\n [mainEventSegments, markerGroups, subAgentGroups, subAgentLanes, toolCallGroups, turnBars],\n );\n\n const barDataset = ({\n label,\n range,\n y,\n color,\n hover,\n thickness,\n order = 1,\n inflateAmount,\n }: {\n label: string;\n range: TimelineGap;\n y: number;\n color: string;\n hover: string;\n thickness: number;\n order?: number;\n inflateAmount?: number;\n }) => ({\n label,\n data: [{ x: getTimelineRange(range), y }] satisfies BarPoint[],\n backgroundColor: color,\n hoverBackgroundColor: hover,\n hoverBorderColor: hover,\n borderWidth: 0,\n borderSkipped: false,\n borderRadius: BAR_RADIUS_PX,\n minBarLength: MARKER_PX,\n barThickness: thickness,\n grouped: false,\n order,\n ...(inflateAmount == null ? {} : { inflateAmount }),\n });\n\n const chartData = useMemo<ChartData<TimelineChartType, Array<BarPoint | MarkerPoint>, string>>(\n () => ({\n datasets: [\n ...turnBars.map(bar =>\n barDataset({\n label: `Turn ${bar.ordinal + 1}`,\n range: bar,\n y: centers[0] ?? 0,\n color: turnFill,\n hover: turnHover,\n thickness: 16,\n }),\n ),\n ...markerGroups.map(group => {\n const type = group.segments.length === 1 ? group.segments[0]?.type : 'system';\n const color = getSessionEventColor(type ?? 'system', isDark);\n return {\n type: 'scatter' as const,\n label: group.segments.map(segment => getSessionEventLabel(segment.type)).join(', '),\n data: [{ x: group.startMs, y: centers[markerRow] ?? 0 }] satisfies MarkerPoint[],\n pointStyle: 'rectRot' as const,\n pointRadius: 5,\n pointHoverRadius: 6,\n clip: false,\n backgroundColor: color,\n hoverBackgroundColor: getSessionEventHoverColor(type ?? 'system', isDark),\n borderWidth: 0,\n order: 0,\n } satisfies ChartDataset<'scatter', MarkerPoint[]>;\n }),\n ...subAgentLanes.flatMap(lane =>\n lane.segments.map(segment =>\n barDataset({\n label: `${getSessionEventLabel(segment.type)}: ${segment.title}`,\n range: segment,\n y: centers[eventRow + 1 + lane.lane] ?? 0,\n color: getSessionEventColor(segment.type, isDark),\n hover: getSessionEventHoverColor(segment.type, isDark),\n thickness: 12,\n order: eventOrder(segment.type),\n inflateAmount: 0.5,\n }),\n ),\n ),\n ...mainEventSegments.map(segment =>\n barDataset({\n label: `${getSessionEventLabel(segment.type)}: ${segment.title}`,\n range: segment,\n y: centers[eventRow] ?? 0,\n color: getSessionEventColor(segment.type, isDark),\n hover: getSessionEventHoverColor(segment.type, isDark),\n thickness: 28,\n order: eventOrder(segment.type),\n inflateAmount: 0.5,\n }),\n ),\n ...toolCallGroups.map(group =>\n barDataset({\n label: 'Parallel tool calls',\n range: group,\n y: centers[eventRow] ?? 0,\n color: getSessionEventColor('tool_call', isDark),\n hover: getSessionEventHoverColor('tool_call', isDark),\n thickness: 28,\n order: eventOrder('tool_call'),\n inflateAmount: 0.5,\n }),\n ),\n ],\n }),\n [\n centers,\n eventRow,\n isDark,\n mainEventSegments,\n markerGroups,\n markerRow,\n subAgentLanes,\n toolCallGroups,\n turnBars,\n turnFill,\n turnHover,\n ],\n );\n\n const turnLabelPlugin = useMemo<Plugin<TimelineChartType>>(\n () => ({\n id: 'turnLabels',\n afterDatasetsDraw(chart) {\n const { ctx } = chart;\n ctx.save();\n ctx.fillStyle = axis;\n ctx.font = '500 10px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n turnBars.forEach((bar, index) => {\n const element = chart.getDatasetMeta(index).data[0];\n if (element == null) return;\n const point = turnBarLabelPoint(element);\n if (point) ctx.fillText(`T${bar.ordinal + 1}`, point.x, point.y);\n });\n ctx.restore();\n },\n }),\n [axis, turnBars],\n );\n const overheadPlugin = useMemo<Plugin<TimelineChartType>>(\n () => ({\n id: 'timelineOverhead',\n afterLayout(chart) {\n const next = Math.round(chart.height - chart.chartArea.height);\n setOverheadPx(previous => (previous === next ? previous : next));\n },\n }),\n [],\n );\n\n const chartOptions = useMemo<ChartOptions<TimelineChartType>>(\n () => ({\n indexAxis: 'y',\n animation: false,\n responsive: true,\n maintainAspectRatio: false,\n onClick: (_event, elements) => {\n const target = chartTargets[elements[0]?.datasetIndex ?? -1];\n if (target?.type === TIMELINE_TYPE.turn) onSelectTurn?.(target.bar.turnIndex);\n },\n onHover: (event, elements) => {\n const hoveredDatasetIndex = elements[0]?.datasetIndex;\n const next = hoveredDatasetIndex == null ? null : (chartTargets[hoveredDatasetIndex] ?? null);\n const native = event.native;\n if (native?.target instanceof HTMLElement) {\n native.target.style.cursor = next?.type === TIMELINE_TYPE.turn ? 'pointer' : 'default';\n }\n if (native instanceof MouseEvent) {\n tooltipCursorXRef.current = native.clientX;\n refreshTooltipAnchor();\n }\n // Pointer between bars keeps the current tooltip; a bar without a tooltip dismisses it.\n if (hoveredDatasetIndex == null) return;\n const nextId = getTimelineHoverTargetId(next);\n if (tooltipIdRef.current === nextId) return;\n tooltipIdRef.current = nextId;\n setTooltipTarget(next);\n if (next == null) {\n setTooltipAnchor(null);\n return;\n }\n refreshTooltipAnchor();\n },\n plugins: { legend: { display: false }, tooltip: { enabled: false } },\n scales: {\n x: {\n type: 'linear',\n position: 'top',\n min: 0,\n max: timelineMaxMs,\n grid: { color: grid },\n border: { color: grid },\n afterBuildTicks: scale => {\n scale.ticks = buildTimelineAxisTicks({ activeTotalMs, turnStartsMs: activeTurnStartsMs, turnGapMs });\n },\n ticks: {\n color: axis,\n align: 'inner',\n autoSkip: false,\n includeBounds: false,\n maxTicksLimit: 9,\n callback: value => {\n const timelineMs = Number(value);\n return timelineMs <= totalMs\n ? formatTimelineAxisDuration(getActiveTimelineMs(timelineMs, timelineGaps))\n : '';\n },\n },\n },\n y: {\n type: 'linear',\n display: false,\n reverse: true,\n offset: false,\n min: 0,\n max: band,\n grid: { display: false },\n },\n },\n }),\n [\n activeTotalMs,\n activeTurnStartsMs,\n axis,\n band,\n chartTargets,\n grid,\n onSelectTurn,\n refreshTooltipAnchor,\n timelineGaps,\n timelineMaxMs,\n totalMs,\n turnGapMs,\n ],\n );\n\n const tooltipTurn = tooltipTarget?.type === TIMELINE_TYPE.turn ? turns[tooltipTarget.bar.turnIndex] : undefined;\n const containerStyle = useMemo<CSSProperties>(() => ({ height: band + overheadPx }), [band, overheadPx]);\n const tooltipContent =\n tooltipTarget?.type === TIMELINE_TYPE.turn && tooltipTurn != null ? (\n <SessionTurnTooltip\n turn={tooltipTurn}\n turnNumber={tooltipTarget.bar.ordinal + 1}\n durationMs={tooltipTarget.bar.durationMs}\n segments={segments.filter(segment => segment.turnIndex === tooltipTarget.bar.turnIndex)}\n />\n ) : tooltipTarget?.type === TIMELINE_TYPE.event && hasSessionEventTooltip(tooltipTarget.segment) ? (\n <SessionEventTooltip\n segment={tooltipTarget.segment}\n subAgentLabel={\n tooltipTarget.segment.type === 'sub_agent'\n ? undefined\n : subAgentLanes.find(lane => lane.threadId === tooltipTarget.segment.threadId)?.track.description\n }\n />\n ) : tooltipTarget?.type === TIMELINE_TYPE.toolCallGroup ? (\n <SessionToolCallGroupTooltip group={tooltipTarget.group} />\n ) : tooltipTarget?.type === TIMELINE_TYPE.markerGroup ? (\n <SessionMarkerGroupTooltip group={tooltipTarget.group} />\n ) : tooltipTarget?.type === TIMELINE_TYPE.subAgentGroup ? (\n <SessionSubAgentGroupTooltip group={tooltipTarget.group} />\n ) : null;\n\n return (\n <div ref={wrapperRef} className=\"w-full\" data-slot=\"agent-session-event-timeline-chart\">\n <LightTooltip\n title={tooltipContent}\n side=\"bottom\"\n triggerClassName=\"block w-full\"\n followCursor\n open={tooltipTarget != null && tooltipContent != null}\n className=\"max-w-[min(25rem,calc(100vw-1rem))] whitespace-normal\"\n anchor={tooltipAnchor}\n >\n <div className=\"w-full\" style={containerStyle} onMouseLeave={clearTooltip}>\n <Chart<TimelineChartType, Array<BarPoint | MarkerPoint>, string>\n type=\"bar\"\n data={chartData}\n options={chartOptions}\n plugins={[turnLabelPlugin, overheadPlugin]}\n />\n </div>\n </LightTooltip>\n </div>\n );\n}\n\ndeclare module '../../theme/SlotsProvider.js' {\n interface AtomSlots {\n AgentSessionEventTimelineChart: ComponentType<AgentSessionEventTimelineChartProps>;\n }\n}\n","'use client';\n\nimport { useThemeMode } from '../../theme/SlotsProvider.js';\nimport { formatCostUsd, formatDurationMs, formatTokenCount } from '../../utils/sessionDisplayFormat.js';\nimport {\n formatTimelineDuration,\n getSessionEventColor,\n getSessionEventTooltipHeading,\n SESSION_EVENT_TOOLTIP_HIDE_DURATION,\n type SessionEventTimelineSegment,\n} from '../../utils/sessionEventTimeline.js';\nimport type {\n TimelineMarkerGroup,\n TimelineSubAgentGroup,\n TimelineToolCallGroup,\n} from '../../utils/sessionEventTimelineChart.js';\nimport type { SessionTurnView } from '../../utils/sessionTurnViews.js';\n\nexport function hasSessionEventTooltip(segment: SessionEventTimelineSegment): boolean {\n return segment.type !== 'system' || segment.description.trim().length > 0;\n}\n\nexport function SessionEventTooltip({\n segment,\n subAgentLabel,\n}: {\n segment: SessionEventTimelineSegment;\n subAgentLabel?: string;\n}) {\n const showDuration = !segment.isMarker && !SESSION_EVENT_TOOLTIP_HIDE_DURATION.has(segment.type);\n const content = segment.description.trim();\n if (segment.type === 'system') {\n if (content.length === 0) return null;\n return (\n <p className=\"max-w-[25rem] whitespace-normal break-words text-xs font-medium text-text-primary\">{content}</p>\n );\n }\n\n return (\n <div className=\"max-h-72 max-w-[25rem] overflow-auto whitespace-normal break-words text-xs\">\n {subAgentLabel != null ? (\n <div className=\"border-b border-border py-1.5 text-text-secondary\">{`Sub-Agent: ${subAgentLabel}`}</div>\n ) : null}\n <div className=\"flex items-center justify-between gap-3 pt-1\">\n <span className={segment.type === 'error' ? 'font-medium text-failure-bg' : 'font-medium text-text-secondary'}>\n {getSessionEventTooltipHeading(segment.type)}\n </span>\n {showDuration ? (\n <span className=\"tabular-nums text-text-secondary\">\n {formatTimelineDuration(segment.endMs - segment.startMs)}\n </span>\n ) : null}\n </div>\n {content.length > 0 ? <p className=\"mt-1.5 line-clamp-6 font-medium text-text-primary\">{content}</p> : null}\n </div>\n );\n}\n\nexport function SessionTurnTooltip({\n turn,\n turnNumber,\n durationMs,\n segments,\n}: {\n turn: SessionTurnView;\n turnNumber: number;\n durationMs: number;\n segments: SessionEventTimelineSegment[];\n}) {\n const isDark = useThemeMode() === 'dark';\n return (\n <div className=\"max-h-72 w-72 max-w-full overflow-auto text-xs text-text-primary\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"font-semibold\">{`Turn ${turnNumber}`}</span>\n <span className=\"tabular-nums text-text-secondary\">{formatDurationMs(durationMs)}</span>\n </div>\n <div className=\"mt-1 flex flex-col text-text-secondary\">\n {turn.totalCostInUsd != null ? <span>{`Cost: ${formatCostUsd(turn.totalCostInUsd)}`}</span> : null}\n {turn.totalTokens != null ? <span>{`Tokens: ${formatTokenCount(turn.totalTokens)}`}</span> : null}\n </div>\n <div className=\"mt-2 border-t border-border pt-2\">\n {segments.map(segment => {\n const label =\n segment.type === 'tool_call' || segment.type === 'sub_agent' ? segment.description : segment.title;\n return (\n <div key={segment.id} className=\"flex min-w-0 items-center gap-1.5\">\n <span\n className=\"size-1.5 shrink-0 rounded-full\"\n style={{ backgroundColor: getSessionEventColor(segment.type, isDark) }}\n />\n <span className=\"min-w-0 flex-1 truncate\">{label}</span>\n {segment.isMarker ? null : (\n <span className=\"ml-auto shrink-0 tabular-nums text-text-secondary\">\n {formatTimelineDuration(segment.endMs - segment.startMs)}\n </span>\n )}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nexport function SessionToolCallGroupTooltip({ group }: { group: TimelineToolCallGroup }) {\n return (\n <div className=\"max-h-72 w-80 max-w-full overflow-auto text-xs\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"font-medium text-text-secondary\">Tool calls</span>\n <span className=\"tabular-nums text-text-secondary\">{formatTimelineDuration(group.endMs - group.startMs)}</span>\n </div>\n <div className=\"mt-1.5 border-t border-border pt-1.5\">\n {group.segments.map(segment => (\n <div key={segment.id} className=\"flex items-center justify-between gap-2 py-0.5\">\n <span className=\"min-w-0 truncate font-medium text-text-primary\">\n {segment.description || segment.title}\n </span>\n <span className=\"shrink-0 tabular-nums text-text-secondary\">\n {formatTimelineDuration(segment.endMs - segment.startMs)}\n </span>\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nexport function SessionMarkerGroupTooltip({ group }: { group: TimelineMarkerGroup }) {\n const isDark = useThemeMode() === 'dark';\n const singleSegment = group.segments.length === 1 ? group.segments[0] : undefined;\n if (singleSegment != null) return <SessionEventTooltip segment={singleSegment} />;\n\n return (\n <div className=\"max-h-72 w-80 max-w-full overflow-auto text-xs\">\n <span className=\"font-medium text-text-secondary\">Events</span>\n <div className=\"mt-1.5 border-t border-border pt-1.5\">\n {group.segments.map(segment => (\n <div key={segment.id} className=\"flex min-w-0 items-start gap-1.5 py-0.5\">\n <span\n className=\"mt-1 size-1.5 shrink-0 rounded-full\"\n style={{ backgroundColor: getSessionEventColor(segment.type, isDark) }}\n />\n <div className=\"min-w-0\">\n <div className=\"font-medium text-text-secondary\">{getSessionEventTooltipHeading(segment.type)}</div>\n <div className=\"wrap-break-word font-medium text-text-primary\">\n {segment.description.trim() || segment.title}\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nexport function SessionSubAgentGroupTooltip({ group }: { group: TimelineSubAgentGroup }) {\n return (\n <div className=\"max-h-72 w-80 max-w-full overflow-auto text-xs\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"font-medium text-text-secondary\">Sub-agents</span>\n <span className=\"tabular-nums text-text-secondary\">{formatTimelineDuration(group.endMs - group.startMs)}</span>\n </div>\n <div className=\"mt-1.5 border-t border-border pt-1.5\">\n {group.segments.map((segment, index) => (\n <div key={segment.id} className=\"flex items-center justify-between gap-2 py-0.5\">\n <span className=\"min-w-0 truncate font-medium text-text-primary\">\n {group.segments.length === 1\n ? segment.description || segment.title\n : `Sub-agent ${index + 1}: ${segment.description || segment.title}`}\n </span>\n {group.segments.length === 1 ? null : (\n <span className=\"shrink-0 tabular-nums text-text-secondary\">\n {formatTimelineDuration(segment.endMs - segment.startMs)}\n </span>\n )}\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AACP,SAAS,aAAa,WAAW,SAAS,QAAQ,gBAAwD;AAC1G,SAAS,aAAa;;;ACkBhB,cASA,YATA;AAhBC,SAAS,uBAAuB,SAA+C;AACpF,SAAO,QAAQ,SAAS,YAAY,QAAQ,YAAY,KAAK,EAAE,SAAS;AAC1E;AAEO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AACF,GAGG;AACD,QAAM,eAAe,CAAC,QAAQ,YAAY,CAAC,oCAAoC,IAAI,QAAQ,IAAI;AAC/F,QAAM,UAAU,QAAQ,YAAY,KAAK;AACzC,MAAI,QAAQ,SAAS,UAAU;AAC7B,QAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,WACE,oBAAC,OAAE,WAAU,qFAAqF,mBAAQ;AAAA,EAE9G;AAEA,SACE,qBAAC,SAAI,WAAU,8EACZ;AAAA,qBAAiB,OAChB,oBAAC,SAAI,WAAU,qDAAqD,wBAAc,aAAa,IAAG,IAChG;AAAA,IACJ,qBAAC,SAAI,WAAU,gDACb;AAAA,0BAAC,UAAK,WAAW,QAAQ,SAAS,UAAU,gCAAgC,mCACzE,wCAA8B,QAAQ,IAAI,GAC7C;AAAA,MACC,eACC,oBAAC,UAAK,WAAU,oCACb,iCAAuB,QAAQ,QAAQ,QAAQ,OAAO,GACzD,IACE;AAAA,OACN;AAAA,IACC,QAAQ,SAAS,IAAI,oBAAC,OAAE,WAAU,qDAAqD,mBAAQ,IAAO;AAAA,KACzG;AAEJ;AAEO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,SAAS,aAAa,MAAM;AAClC,SACE,qBAAC,SAAI,WAAU,oEACb;AAAA,yBAAC,SAAI,WAAU,2CACb;AAAA,0BAAC,UAAK,WAAU,iBAAiB,kBAAQ,UAAU,IAAG;AAAA,MACtD,oBAAC,UAAK,WAAU,oCAAoC,2BAAiB,UAAU,GAAE;AAAA,OACnF;AAAA,IACA,qBAAC,SAAI,WAAU,0CACZ;AAAA,WAAK,kBAAkB,OAAO,oBAAC,UAAM,mBAAS,cAAc,KAAK,cAAc,CAAC,IAAG,IAAU;AAAA,MAC7F,KAAK,eAAe,OAAO,oBAAC,UAAM,qBAAW,iBAAiB,KAAK,WAAW,CAAC,IAAG,IAAU;AAAA,OAC/F;AAAA,IACA,oBAAC,SAAI,WAAU,oCACZ,mBAAS,IAAI,aAAW;AACvB,YAAM,QACJ,QAAQ,SAAS,eAAe,QAAQ,SAAS,cAAc,QAAQ,cAAc,QAAQ;AAC/F,aACE,qBAAC,SAAqB,WAAU,qCAC9B;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,iBAAiB,qBAAqB,QAAQ,MAAM,MAAM,EAAE;AAAA;AAAA,QACvE;AAAA,QACA,oBAAC,UAAK,WAAU,2BAA2B,iBAAM;AAAA,QAChD,QAAQ,WAAW,OAClB,oBAAC,UAAK,WAAU,qDACb,iCAAuB,QAAQ,QAAQ,QAAQ,OAAO,GACzD;AAAA,WATM,QAAQ,EAWlB;AAAA,IAEJ,CAAC,GACH;AAAA,KACF;AAEJ;AAEO,SAAS,4BAA4B,EAAE,MAAM,GAAqC;AACvF,SACE,qBAAC,SAAI,WAAU,kDACb;AAAA,yBAAC,SAAI,WAAU,2CACb;AAAA,0BAAC,UAAK,WAAU,mCAAkC,wBAAU;AAAA,MAC5D,oBAAC,UAAK,WAAU,oCAAoC,iCAAuB,MAAM,QAAQ,MAAM,OAAO,GAAE;AAAA,OAC1G;AAAA,IACA,oBAAC,SAAI,WAAU,wCACZ,gBAAM,SAAS,IAAI,aAClB,qBAAC,SAAqB,WAAU,kDAC9B;AAAA,0BAAC,UAAK,WAAU,kDACb,kBAAQ,eAAe,QAAQ,OAClC;AAAA,MACA,oBAAC,UAAK,WAAU,6CACb,iCAAuB,QAAQ,QAAQ,QAAQ,OAAO,GACzD;AAAA,SANQ,QAAQ,EAOlB,CACD,GACH;AAAA,KACF;AAEJ;AAEO,SAAS,0BAA0B,EAAE,MAAM,GAAmC;AACnF,QAAM,SAAS,aAAa,MAAM;AAClC,QAAM,gBAAgB,MAAM,SAAS,WAAW,IAAI,MAAM,SAAS,CAAC,IAAI;AACxE,MAAI,iBAAiB,KAAM,QAAO,oBAAC,uBAAoB,SAAS,eAAe;AAE/E,SACE,qBAAC,SAAI,WAAU,kDACb;AAAA,wBAAC,UAAK,WAAU,mCAAkC,oBAAM;AAAA,IACxD,oBAAC,SAAI,WAAU,wCACZ,gBAAM,SAAS,IAAI,aAClB,qBAAC,SAAqB,WAAU,2CAC9B;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,EAAE,iBAAiB,qBAAqB,QAAQ,MAAM,MAAM,EAAE;AAAA;AAAA,MACvE;AAAA,MACA,qBAAC,SAAI,WAAU,WACb;AAAA,4BAAC,SAAI,WAAU,mCAAmC,wCAA8B,QAAQ,IAAI,GAAE;AAAA,QAC9F,oBAAC,SAAI,WAAU,iDACZ,kBAAQ,YAAY,KAAK,KAAK,QAAQ,OACzC;AAAA,SACF;AAAA,SAVQ,QAAQ,EAWlB,CACD,GACH;AAAA,KACF;AAEJ;AAEO,SAAS,4BAA4B,EAAE,MAAM,GAAqC;AACvF,SACE,qBAAC,SAAI,WAAU,kDACb;AAAA,yBAAC,SAAI,WAAU,2CACb;AAAA,0BAAC,UAAK,WAAU,mCAAkC,wBAAU;AAAA,MAC5D,oBAAC,UAAK,WAAU,oCAAoC,iCAAuB,MAAM,QAAQ,MAAM,OAAO,GAAE;AAAA,OAC1G;AAAA,IACA,oBAAC,SAAI,WAAU,wCACZ,gBAAM,SAAS,IAAI,CAAC,SAAS,UAC5B,qBAAC,SAAqB,WAAU,kDAC9B;AAAA,0BAAC,UAAK,WAAU,kDACb,gBAAM,SAAS,WAAW,IACvB,QAAQ,eAAe,QAAQ,QAC/B,aAAa,QAAQ,CAAC,KAAK,QAAQ,eAAe,QAAQ,KAAK,IACrE;AAAA,MACC,MAAM,SAAS,WAAW,IAAI,OAC7B,oBAAC,UAAK,WAAU,6CACb,iCAAuB,QAAQ,QAAQ,QAAQ,OAAO,GACzD;AAAA,SATM,QAAQ,EAWlB,CACD,GACH;AAAA,KACF;AAEJ;;;AD8TM,gBAAAA,YAAA;AA3bN,QAAQ,SAAS,eAAe,YAAY,aAAa,cAAc,mBAAmB,OAAO;AAEjG,IAAM,YAAY;AAClB,IAAM,cAAc;AACpB,IAAM,aAAa;AACnB,IAAM,gBAAgB;AACtB,IAAM,aAAa;AACnB,IAAM,sBAAsB;AAC5B,IAAM,cAAc;AAMpB,SAAS,WAAW,EAAE,SAAS,KAAK,GAA+E;AACjH,QAAM,UAAoB,CAAC;AAC3B,MAAI,SAAS;AACb,UAAQ,QAAQ,CAAC,QAAQ,UAAU;AACjC,YAAQ,KAAK,SAAS,SAAS,CAAC;AAChC,cAAU,UAAU,KAAK,KAAK,KAAK;AAAA,EACrC,CAAC;AACD,SAAO,EAAE,SAAS,MAAM,OAAO;AACjC;AAEA,SAAS,WAAW,MAAmD;AACrE,MAAI,SAAS,YAAa,QAAO;AACjC,MAAI,SAAS,QAAS,QAAO;AAC7B,SAAO;AACT;AAEA,SAAS,kBAAkB,SAAkD;AAC3E,MAAI,EAAE,OAAO,YAAY,EAAE,OAAO,YAAY,EAAE,UAAU,SAAU,QAAO;AAC3E,QAAM,EAAE,GAAG,GAAG,KAAK,IAAI;AACvB,MAAI,OAAO,MAAM,YAAY,OAAO,MAAM,YAAY,OAAO,SAAS,SAAU,QAAO;AACvF,SAAO,EAAE,IAAI,IAAI,QAAQ,GAAG,EAAE;AAChC;AAEO,SAAS,+BAA+B;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwC;AACtC,QAAM,OAAO,aAAa;AAC1B,QAAM,SAAS,SAAS;AACxB,QAAM,OAAO,SAAS,YAAY;AAClC,QAAM,OAAO,SAAS,YAAY;AAClC,QAAM,WAAW,SAAS,YAAY;AACtC,QAAM,YAAY,SAAS,YAAY;AACvC,QAAM,aAAa,OAAuB,IAAI;AAC9C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,CAAC;AACxC,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,WAAW;AACxD,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAqC,IAAI;AACnF,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAA+C,IAAI;AAC7F,QAAM,eAAe,OAAO,EAAE;AAC9B,QAAM,oBAAoB,OAAsB,IAAI;AAEpD,YAAU,MAAM;AACd,UAAM,UAAU,WAAW;AAC3B,QAAI,WAAW,KAAM,QAAO;AAC5B,UAAM,SAAS,MAAM,WAAW,QAAQ,WAAW;AACnD,WAAO;AACP,UAAM,WAAW,IAAI,eAAe,MAAM;AAC1C,aAAS,QAAQ,OAAO;AACxB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,CAAC;AAEL,QAAM,uBAAuB,YAAY,MAAM;AAC7C,UAAM,UAAU,WAAW;AAC3B,UAAM,OAAO,kBAAkB;AAC/B,QAAI,WAAW,QAAQ,QAAQ,KAAM;AACrC,qBAAiB,EAAE,MAAM,KAAK,QAAQ,sBAAsB,EAAE,OAAO,CAAC;AAAA,EACxE,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,YAAY,MAAM;AACrC,iBAAa,UAAU;AACvB,sBAAkB,UAAU;AAC5B,qBAAiB,IAAI;AACrB,qBAAiB,IAAI;AAAA,EACvB,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI,iBAAiB,KAAM,QAAO;AAGlC,yBAAqB;AACrB,WAAO,iBAAiB,UAAU,sBAAsB,IAAI;AAC5D,WAAO,iBAAiB,UAAU,oBAAoB;AACtD,WAAO,MAAM;AACX,aAAO,oBAAoB,UAAU,sBAAsB,IAAI;AAC/D,aAAO,oBAAoB,UAAU,oBAAoB;AAAA,IAC3D;AAAA,EACF,GAAG,CAAC,sBAAsB,aAAa,CAAC;AAExC,QAAM,iBAAiB,KAAK,IAAI,GAAG,GAAG,SAAS,IAAI,aAAW,QAAQ,KAAK,CAAC;AAC5E,QAAM,gBAAgB,KAAK,IAAI,GAAG,wBAAwB,cAAc,CAAC;AACzE,QAAM,EAAE,cAAc,cAAc,WAAW,IAAI,QAAQ,MAAM,kBAAkB,QAAQ,GAAG,CAAC,QAAQ,CAAC;AACxG,QAAM,qBAAqB;AAAA,IACzB,MAAM,aAAa,OAAO,CAAC,SAAS,UAAU,UAAU,KAAK,WAAW,aAAa;AAAA,IACrF,CAAC,eAAe,YAAY;AAAA,EAC9B;AACA,QAAM,WAAW,KAAK,IAAI,GAAG,mBAAmB,SAAS,CAAC;AAC1D,QAAM,eAAe,KAAK,IAAI,UAAU,GAAG,UAAU,cAAc,WAAW,UAAU;AACxF,QAAM,UAAU,gBAAgB,KAAK,IAAI,GAAG,YAAY;AACxD,QAAM,YAAY,cAAc;AAChC,QAAM,UAAU,gBAAgB,WAAW;AAC3C,QAAM,gBAAgB,UAAU,aAAa;AAC7C,QAAM,eAAe;AAAA,IACnB,MACE,mBACG,MAAM,CAAC,EACP,IAAI,CAAC,SAAS,WAAW,EAAE,SAAS,UAAU,QAAQ,WAAW,OAAO,WAAW,QAAQ,KAAK,UAAU,EAAE;AAAA,IACjH,CAAC,oBAAoB,SAAS;AAAA,EAChC;AAEA,QAAM,kBAAkB;AAAA,IACtB,MACE,SAAS,QAAQ,aAAW;AAC1B,UAAI,YAAY,IAAI,QAAQ,IAAI,EAAG,QAAO,CAAC;AAC3C,YAAM,WAAW,aAAa,IAAI,QAAQ,SAAS,KAAK,KAAK;AAC7D,aAAO,CAAC,EAAE,GAAG,SAAS,SAAS,QAAQ,UAAU,SAAS,OAAO,QAAQ,QAAQ,QAAQ,CAAC;AAAA,IAC5F,CAAC;AAAA,IACH,CAAC,aAAa,UAAU,WAAW,YAAY;AAAA,EACjD;AACA,QAAM,eAAe,QAAQ,MAAM,+BAA+B,eAAe,GAAG,CAAC,eAAe,CAAC;AACrG,QAAM,mBAAmB,QAAQ,MAAM,gBAAgB,OAAO,aAAW,CAAC,QAAQ,QAAQ,GAAG,CAAC,eAAe,CAAC;AAC9G,QAAM,WAAW;AAAA,IACf,MACE,WAAW,SAAS,IAChB,CAAC,IACD,WAAW,IAAI,YAAU;AAAA,MACvB,GAAG;AAAA,MACH,IAAI,QAAQ,MAAM,SAAS;AAAA,MAC3B,YAAY,MAAM,QAAQ,MAAM;AAAA,MAChC,SAAS,MAAM,UAAU,MAAM,UAAU;AAAA,MACzC,OAAO,MAAM,QAAQ,MAAM,UAAU,YAAY,YAAY;AAAA,IAC/D,EAAE;AAAA,IACR,CAAC,SAAS,WAAW,UAAU;AAAA,EACjC;AACA,QAAM,mBAAmB;AAAA,IACvB,MAAM,iBAAiB,OAAO,aAAW,QAAQ,SAAS,WAAW;AAAA,IACrE,CAAC,gBAAgB;AAAA,EACnB;AACA,QAAM,gBAAgB,QAAQ,MAAM,iCAAiC,gBAAgB,GAAG,CAAC,gBAAgB,CAAC;AAC1G,QAAM,iBAAiB;AAAA,IACrB,MAAM,uBAAuB,EAAE,MAAM,eAAe,iBAAiB,CAAC;AAAA,IACtE,CAAC,eAAe,gBAAgB;AAAA,EAClC;AACA,QAAM,gBAAgB;AAAA,IACpB,MAAM,iBAAiB,EAAE,kBAAkB,gBAAgB,kBAAkB,YAAY,YAAY,QAAQ,CAAC;AAAA,IAC9G,CAAC,kBAAkB,SAAS,gBAAgB;AAAA,EAC9C;AACA,QAAM,iBAAiB,QAAQ,MAAM;AACnC,WAAO,CAAC,GAAG,iBAAiB,OAAO,aAAW,QAAQ,aAAa,cAAc,GAAG,GAAG,aAAa,EAAE;AAAA,MACpG,CAAC,MAAM,UAAU,KAAK,UAAU,MAAM,WAAW,KAAK,QAAQ,MAAM;AAAA,IACtE;AAAA,EACF,GAAG,CAAC,kBAAkB,aAAa,CAAC;AACpC,QAAM,iBAAiB;AAAA,IACrB,MACE,0BAA0B,eAAe,OAAO,aAAW,QAAQ,SAAS,WAAW,CAAC,EAAE;AAAA,MACxF,WAAS,MAAM,SAAS,SAAS;AAAA,IACnC;AAAA,IACF,CAAC,cAAc;AAAA,EACjB;AACA,QAAM,aAAa;AAAA,IACjB,MAAM,IAAI,IAAI,eAAe,QAAQ,WAAS,MAAM,SAAS,IAAI,aAAW,QAAQ,EAAE,CAAC,CAAC;AAAA,IACxF,CAAC,cAAc;AAAA,EACjB;AACA,QAAM,oBAAoB;AAAA,IACxB,MAAM,eAAe,OAAO,aAAW,CAAC,WAAW,IAAI,QAAQ,EAAE,CAAC;AAAA,IAClE,CAAC,YAAY,cAAc;AAAA,EAC7B;AACA,QAAM,YAAY,cAAc,OAAO,CAAC,OAAO,SAAS,KAAK,IAAI,OAAO,KAAK,OAAO,CAAC,GAAG,CAAC;AACzF,QAAM,aAAa,SAAS,SAAS;AACrC,QAAM,YAAY,aAAa,IAAI;AACnC,QAAM,WAAW,YAAY;AAC7B,QAAM,EAAE,SAAS,KAAK,IAAI,QAAQ,MAAM;AACtC,UAAM,UAAU,CAAC,GAAI,aAAa,CAAC,EAAE,IAAI,CAAC,GAAI,IAAI,IAAI,GAAG,MAAM,KAAK,EAAE,QAAQ,UAAU,GAAG,MAAM,EAAE,CAAC;AACpG,UAAM,OAAO,QAAQ,IAAI,CAAC,GAAG,UAAU;AACrC,UAAI,UAAU,QAAQ,SAAS,EAAG,QAAO;AACzC,aAAO,UAAU,YAAY,sBAAsB;AAAA,IACrD,CAAC;AACD,WAAO,WAAW,EAAE,SAAS,KAAK,CAAC;AAAA,EACrC,GAAG,CAAC,YAAY,WAAW,SAAS,CAAC;AAErC,QAAM,eAAe;AAAA,IACnB,MAAM;AAAA,MACJ,GAAG,SAAS,IAAI,CAAC,SAA8B,EAAE,MAAM,cAAc,MAAM,IAAI,EAAE;AAAA,MACjF,GAAG,aAAa,IAAI,CAAC,WAAgC,EAAE,MAAM,cAAc,aAAa,MAAM,EAAE;AAAA,MAChG,GAAG,cAAc;AAAA,QAAQ,UACvB,KAAK,SAAS,IAAI,CAAC,aAAkC,EAAE,MAAM,cAAc,OAAO,QAAQ,EAAE;AAAA,MAC9F;AAAA,MACA,GAAG,kBAAkB,IAAI,CAAC,YAAwC;AAChE,YAAI,QAAQ,SAAS,YAAa,QAAO,EAAE,MAAM,cAAc,OAAO,QAAQ;AAC9E,cAAM,QAAQ,eAAe,KAAK,eAAa,UAAU,UAAU,QAAQ,EAAE;AAC7E,eAAO,SAAS,OAAO,EAAE,MAAM,cAAc,OAAO,QAAQ,IAAI,EAAE,MAAM,cAAc,eAAe,MAAM;AAAA,MAC7G,CAAC;AAAA,MACD,GAAG,eAAe,IAAI,CAAC,WAAgC,EAAE,MAAM,cAAc,eAAe,MAAM,EAAE;AAAA,IACtG;AAAA,IACA,CAAC,mBAAmB,cAAc,gBAAgB,eAAe,gBAAgB,QAAQ;AAAA,EAC3F;AAEA,QAAM,aAAa,CAAC;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,EACF,OASO;AAAA,IACL;AAAA,IACA,MAAM,CAAC,EAAE,GAAG,iBAAiB,KAAK,GAAG,EAAE,CAAC;AAAA,IACxC,iBAAiB;AAAA,IACjB,sBAAsB;AAAA,IACtB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,eAAe;AAAA,IACf,cAAc;AAAA,IACd,cAAc;AAAA,IACd,cAAc;AAAA,IACd,SAAS;AAAA,IACT;AAAA,IACA,GAAI,iBAAiB,OAAO,CAAC,IAAI,EAAE,cAAc;AAAA,EACnD;AAEA,QAAM,YAAY;AAAA,IAChB,OAAO;AAAA,MACL,UAAU;AAAA,QACR,GAAG,SAAS;AAAA,UAAI,SACd,WAAW;AAAA,YACT,OAAO,QAAQ,IAAI,UAAU,CAAC;AAAA,YAC9B,OAAO;AAAA,YACP,GAAG,QAAQ,CAAC,KAAK;AAAA,YACjB,OAAO;AAAA,YACP,OAAO;AAAA,YACP,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAAA,QACA,GAAG,aAAa,IAAI,WAAS;AAC3B,gBAAM,OAAO,MAAM,SAAS,WAAW,IAAI,MAAM,SAAS,CAAC,GAAG,OAAO;AACrE,gBAAM,QAAQ,qBAAqB,QAAQ,UAAU,MAAM;AAC3D,iBAAO;AAAA,YACL,MAAM;AAAA,YACN,OAAO,MAAM,SAAS,IAAI,aAAW,qBAAqB,QAAQ,IAAI,CAAC,EAAE,KAAK,IAAI;AAAA,YAClF,MAAM,CAAC,EAAE,GAAG,MAAM,SAAS,GAAG,QAAQ,SAAS,KAAK,EAAE,CAAC;AAAA,YACvD,YAAY;AAAA,YACZ,aAAa;AAAA,YACb,kBAAkB;AAAA,YAClB,MAAM;AAAA,YACN,iBAAiB;AAAA,YACjB,sBAAsB,0BAA0B,QAAQ,UAAU,MAAM;AAAA,YACxE,aAAa;AAAA,YACb,OAAO;AAAA,UACT;AAAA,QACF,CAAC;AAAA,QACD,GAAG,cAAc;AAAA,UAAQ,UACvB,KAAK,SAAS;AAAA,YAAI,aAChB,WAAW;AAAA,cACT,OAAO,GAAG,qBAAqB,QAAQ,IAAI,CAAC,KAAK,QAAQ,KAAK;AAAA,cAC9D,OAAO;AAAA,cACP,GAAG,QAAQ,WAAW,IAAI,KAAK,IAAI,KAAK;AAAA,cACxC,OAAO,qBAAqB,QAAQ,MAAM,MAAM;AAAA,cAChD,OAAO,0BAA0B,QAAQ,MAAM,MAAM;AAAA,cACrD,WAAW;AAAA,cACX,OAAO,WAAW,QAAQ,IAAI;AAAA,cAC9B,eAAe;AAAA,YACjB,CAAC;AAAA,UACH;AAAA,QACF;AAAA,QACA,GAAG,kBAAkB;AAAA,UAAI,aACvB,WAAW;AAAA,YACT,OAAO,GAAG,qBAAqB,QAAQ,IAAI,CAAC,KAAK,QAAQ,KAAK;AAAA,YAC9D,OAAO;AAAA,YACP,GAAG,QAAQ,QAAQ,KAAK;AAAA,YACxB,OAAO,qBAAqB,QAAQ,MAAM,MAAM;AAAA,YAChD,OAAO,0BAA0B,QAAQ,MAAM,MAAM;AAAA,YACrD,WAAW;AAAA,YACX,OAAO,WAAW,QAAQ,IAAI;AAAA,YAC9B,eAAe;AAAA,UACjB,CAAC;AAAA,QACH;AAAA,QACA,GAAG,eAAe;AAAA,UAAI,WACpB,WAAW;AAAA,YACT,OAAO;AAAA,YACP,OAAO;AAAA,YACP,GAAG,QAAQ,QAAQ,KAAK;AAAA,YACxB,OAAO,qBAAqB,aAAa,MAAM;AAAA,YAC/C,OAAO,0BAA0B,aAAa,MAAM;AAAA,YACpD,WAAW;AAAA,YACX,OAAO,WAAW,WAAW;AAAA,YAC7B,eAAe;AAAA,UACjB,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,kBAAkB;AAAA,IACtB,OAAO;AAAA,MACL,IAAI;AAAA,MACJ,kBAAkB,OAAO;AACvB,cAAM,EAAE,IAAI,IAAI;AAChB,YAAI,KAAK;AACT,YAAI,YAAY;AAChB,YAAI,OAAO;AACX,YAAI,YAAY;AAChB,YAAI,eAAe;AACnB,iBAAS,QAAQ,CAAC,KAAK,UAAU;AAC/B,gBAAM,UAAU,MAAM,eAAe,KAAK,EAAE,KAAK,CAAC;AAClD,cAAI,WAAW,KAAM;AACrB,gBAAM,QAAQ,kBAAkB,OAAO;AACvC,cAAI,MAAO,KAAI,SAAS,IAAI,IAAI,UAAU,CAAC,IAAI,MAAM,GAAG,MAAM,CAAC;AAAA,QACjE,CAAC;AACD,YAAI,QAAQ;AAAA,MACd;AAAA,IACF;AAAA,IACA,CAAC,MAAM,QAAQ;AAAA,EACjB;AACA,QAAM,iBAAiB;AAAA,IACrB,OAAO;AAAA,MACL,IAAI;AAAA,MACJ,YAAY,OAAO;AACjB,cAAM,OAAO,KAAK,MAAM,MAAM,SAAS,MAAM,UAAU,MAAM;AAC7D,sBAAc,cAAa,aAAa,OAAO,WAAW,IAAK;AAAA,MACjE;AAAA,IACF;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,eAAe;AAAA,IACnB,OAAO;AAAA,MACL,WAAW;AAAA,MACX,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,qBAAqB;AAAA,MACrB,SAAS,CAAC,QAAQ,aAAa;AAC7B,cAAM,SAAS,aAAa,SAAS,CAAC,GAAG,gBAAgB,EAAE;AAC3D,YAAI,QAAQ,SAAS,cAAc,KAAM,gBAAe,OAAO,IAAI,SAAS;AAAA,MAC9E;AAAA,MACA,SAAS,CAAC,OAAO,aAAa;AAC5B,cAAM,sBAAsB,SAAS,CAAC,GAAG;AACzC,cAAM,OAAO,uBAAuB,OAAO,OAAQ,aAAa,mBAAmB,KAAK;AACxF,cAAM,SAAS,MAAM;AACrB,YAAI,QAAQ,kBAAkB,aAAa;AACzC,iBAAO,OAAO,MAAM,SAAS,MAAM,SAAS,cAAc,OAAO,YAAY;AAAA,QAC/E;AACA,YAAI,kBAAkB,YAAY;AAChC,4BAAkB,UAAU,OAAO;AACnC,+BAAqB;AAAA,QACvB;AAEA,YAAI,uBAAuB,KAAM;AACjC,cAAM,SAAS,yBAAyB,IAAI;AAC5C,YAAI,aAAa,YAAY,OAAQ;AACrC,qBAAa,UAAU;AACvB,yBAAiB,IAAI;AACrB,YAAI,QAAQ,MAAM;AAChB,2BAAiB,IAAI;AACrB;AAAA,QACF;AACA,6BAAqB;AAAA,MACvB;AAAA,MACA,SAAS,EAAE,QAAQ,EAAE,SAAS,MAAM,GAAG,SAAS,EAAE,SAAS,MAAM,EAAE;AAAA,MACnE,QAAQ;AAAA,QACN,GAAG;AAAA,UACD,MAAM;AAAA,UACN,UAAU;AAAA,UACV,KAAK;AAAA,UACL,KAAK;AAAA,UACL,MAAM,EAAE,OAAO,KAAK;AAAA,UACpB,QAAQ,EAAE,OAAO,KAAK;AAAA,UACtB,iBAAiB,WAAS;AACxB,kBAAM,QAAQ,uBAAuB,EAAE,eAAe,cAAc,oBAAoB,UAAU,CAAC;AAAA,UACrG;AAAA,UACA,OAAO;AAAA,YACL,OAAO;AAAA,YACP,OAAO;AAAA,YACP,UAAU;AAAA,YACV,eAAe;AAAA,YACf,eAAe;AAAA,YACf,UAAU,WAAS;AACjB,oBAAM,aAAa,OAAO,KAAK;AAC/B,qBAAO,cAAc,UACjB,2BAA2B,oBAAoB,YAAY,YAAY,CAAC,IACxE;AAAA,YACN;AAAA,UACF;AAAA,QACF;AAAA,QACA,GAAG;AAAA,UACD,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,KAAK;AAAA,UACL,KAAK;AAAA,UACL,MAAM,EAAE,SAAS,MAAM;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,cAAc,eAAe,SAAS,cAAc,OAAO,MAAM,cAAc,IAAI,SAAS,IAAI;AACtG,QAAM,iBAAiB,QAAuB,OAAO,EAAE,QAAQ,OAAO,WAAW,IAAI,CAAC,MAAM,UAAU,CAAC;AACvG,QAAM,iBACJ,eAAe,SAAS,cAAc,QAAQ,eAAe,OAC3D,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAM;AAAA,MACN,YAAY,cAAc,IAAI,UAAU;AAAA,MACxC,YAAY,cAAc,IAAI;AAAA,MAC9B,UAAU,SAAS,OAAO,aAAW,QAAQ,cAAc,cAAc,IAAI,SAAS;AAAA;AAAA,EACxF,IACE,eAAe,SAAS,cAAc,SAAS,uBAAuB,cAAc,OAAO,IAC7F,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,SAAS,cAAc;AAAA,MACvB,eACE,cAAc,QAAQ,SAAS,cAC3B,SACA,cAAc,KAAK,UAAQ,KAAK,aAAa,cAAc,QAAQ,QAAQ,GAAG,MAAM;AAAA;AAAA,EAE5F,IACE,eAAe,SAAS,cAAc,gBACxC,gBAAAA,KAAC,+BAA4B,OAAO,cAAc,OAAO,IACvD,eAAe,SAAS,cAAc,cACxC,gBAAAA,KAAC,6BAA0B,OAAO,cAAc,OAAO,IACrD,eAAe,SAAS,cAAc,gBACxC,gBAAAA,KAAC,+BAA4B,OAAO,cAAc,OAAO,IACvD;AAEN,SACE,gBAAAA,KAAC,SAAI,KAAK,YAAY,WAAU,UAAS,aAAU,sCACjD,0BAAAA;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,MACP,MAAK;AAAA,MACL,kBAAiB;AAAA,MACjB,cAAY;AAAA,MACZ,MAAM,iBAAiB,QAAQ,kBAAkB;AAAA,MACjD,WAAU;AAAA,MACV,QAAQ;AAAA,MAER,0BAAAA,KAAC,SAAI,WAAU,UAAS,OAAO,gBAAgB,cAAc,cAC3D,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS,CAAC,iBAAiB,cAAc;AAAA;AAAA,MAC3C,GACF;AAAA;AAAA,EACF,GACF;AAEJ;","names":["jsx"]}
@@ -1,41 +1,55 @@
1
1
  "use client";
2
2
  import {
3
3
  buildSessionResumeHref
4
- } from "./chunk-SQGT43Z3.js";
4
+ } from "./chunk-73FQVITT.js";
5
5
  import {
6
6
  useOptionalResolvedRoutes
7
7
  } from "./chunk-Y6S4OVVQ.js";
8
- import {
9
- drainListPages
10
- } from "./chunk-SFZNIO6U.js";
11
8
  import {
12
9
  sessionIsCreateAgent
13
10
  } from "./chunk-RDXBMTP5.js";
14
11
  import {
15
12
  EmptyScreen,
16
13
  Skeleton,
14
+ useResourcePermissions,
17
15
  useSessionShareSearch,
18
16
  useSlot
19
- } from "./chunk-YQO2NMJ3.js";
20
- import "./chunk-NHHSZB5N.js";
17
+ } from "./chunk-2O5EJ6QS.js";
18
+ import "./chunk-KR7WYHVF.js";
21
19
  import {
22
20
  Icon
23
- } from "./chunk-H6WTY5PM.js";
21
+ } from "./chunk-Q6TCT7ZJ.js";
24
22
  import {
25
23
  sessionTimeRangeFromCreatedAt,
26
24
  useAgentSessionsServer,
27
25
  useOptionalShellMode,
28
26
  useServer
29
- } from "./chunk-FQK2XVVE.js";
27
+ } from "./chunk-PT4EENB3.js";
30
28
  import "./chunk-M6MHLVSO.js";
31
- import "./chunk-VJ7BZGAF.js";
29
+ import "./chunk-J5BPHEDT.js";
32
30
  import {
33
31
  cn
34
- } from "./chunk-BWHOZFIV.js";
32
+ } from "./chunk-LXJMINS6.js";
35
33
 
36
34
  // src/atoms/agent-details/AgentSessions.tsx
37
35
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
38
36
  import { Group, Panel, Separator } from "react-resizable-panels";
37
+
38
+ // src/utils/drainListPages.ts
39
+ async function drainListPages({
40
+ fetchPage
41
+ }) {
42
+ const items = [];
43
+ let pageToken;
44
+ do {
45
+ const page = await fetchPage(pageToken);
46
+ items.push(...page.data);
47
+ pageToken = page.nextPageToken;
48
+ } while (pageToken != null && pageToken.length > 0);
49
+ return items;
50
+ }
51
+
52
+ // src/atoms/agent-details/AgentSessions.tsx
39
53
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
40
54
  function sessionTitle(entry) {
41
55
  const title = entry.title?.trim();
@@ -47,12 +61,20 @@ function entryIsMutable(entry) {
47
61
  }
48
62
  return entry.agentName == null;
49
63
  }
64
+ function entrySourceType(entry) {
65
+ return "sourceType" in entry && Reflect.get(entry, "sourceType") === "schedule" ? "schedule" : void 0;
66
+ }
50
67
  function AgentSessions({ agentId, startTimestamp, endTimestamp, shareView }) {
51
68
  const sessionsServer = useAgentSessionsServer();
52
69
  const chatServer = useServer();
53
70
  const shell = useOptionalShellMode();
54
71
  const routes = useOptionalResolvedRoutes();
55
72
  const { sessionId: selectedSessionId, updateShareSearch } = useSessionShareSearch();
73
+ const { allows } = useResourcePermissions({
74
+ resourceType: "session",
75
+ resourceIds: selectedSessionId == null ? [] : [selectedSessionId]
76
+ });
77
+ const canResume = allows(selectedSessionId, "MANAGE");
56
78
  const AgentSessionListRow = useSlot("AgentSessionListRow");
57
79
  const AgentSessionDetailHeader = useSlot("AgentSessionDetailHeader");
58
80
  const AgentSessionTimelineContainer = useSlot("AgentSessionTimelineContainer");
@@ -165,7 +187,7 @@ function AgentSessions({ agentId, startTimestamp, endTimestamp, shareView }) {
165
187
  const resumeLabel = resumeIsCreateAgent ? "Resume Agent building" : "Resume Chat";
166
188
  const resumeHref = selectedSessionId != null && routes != null ? buildSessionResumeHref({ sessionId: selectedSessionId, routes }) : null;
167
189
  const handleResume = () => {
168
- if (selectedSessionId == null || shell == null) return;
190
+ if (!canResume || selectedSessionId == null || shell == null) return;
169
191
  const agentName = detailSession?.agentName ?? selectedEntry?.agentName;
170
192
  shell.openHistorySession({
171
193
  sessionId: selectedSessionId,
@@ -199,6 +221,7 @@ function AgentSessions({ agentId, startTimestamp, endTimestamp, shareView }) {
199
221
  {
200
222
  title: sessionTitle(entry),
201
223
  agentName: entry.agentName ?? void 0,
224
+ sourceType: entrySourceType(entry),
202
225
  lastActivityAt: entry.lastActivityAt,
203
226
  metrics: entry.metrics,
204
227
  active: entry.id === selectedSessionId,
@@ -253,6 +276,7 @@ function AgentSessions({ agentId, startTimestamp, endTimestamp, shareView }) {
253
276
  createdAt: detailSession?.createdAt ?? selectedEntry?.createdAt,
254
277
  view: shareView,
255
278
  onClose: clearSelectedSession,
279
+ canResume,
256
280
  ...resumeProps
257
281
  }
258
282
  ),
@@ -272,4 +296,4 @@ function AgentSessions({ agentId, startTimestamp, endTimestamp, shareView }) {
272
296
  export {
273
297
  AgentSessions
274
298
  };
275
- //# sourceMappingURL=AgentSessions-T7MOGOTZ.js.map
299
+ //# sourceMappingURL=AgentSessions-4IVX2SGD.js.map