@truefoundry/trueforge-ui 0.2.4 → 0.3.0-rc.1
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/CHANGELOG.md +85 -0
- package/README.md +55 -23
- package/dist/AgentCodeSnippets-NZOFJE57.js +74 -0
- package/dist/AgentCodeSnippets-NZOFJE57.js.map +1 -0
- package/dist/AgentMetricChart-JPU3MFQ2.js +15 -0
- package/dist/AgentOverview-EEBHJC32.js +167 -0
- package/dist/AgentOverview-EEBHJC32.js.map +1 -0
- package/dist/AgentSessionEventTimeline-26Z6IB3B.js +79 -0
- package/dist/AgentSessionEventTimeline-26Z6IB3B.js.map +1 -0
- package/dist/AgentSessionEventTimelineChart-CGCU7WBK.js +504 -0
- package/dist/AgentSessionEventTimelineChart-CGCU7WBK.js.map +1 -0
- package/dist/AgentSessions-3MPDZASK.js +275 -0
- package/dist/AgentSessions-3MPDZASK.js.map +1 -0
- package/dist/{ConnectorSettings-ODC3LVHN.js → ConnectorSettings-MXFRWWR6.js} +8 -6
- package/dist/{ConnectorSettings-ODC3LVHN.js.map → ConnectorSettings-MXFRWWR6.js.map} +1 -1
- package/dist/{DockLayout-TEOWEMSV.js → DockLayout-LM4AFMFY.js} +12 -11
- package/dist/{DockLayout-TEOWEMSV.js.map → DockLayout-LM4AFMFY.js.map} +1 -1
- package/dist/DrawerLayout-JR3O6RRB.js +184 -0
- package/dist/DrawerLayout-JR3O6RRB.js.map +1 -0
- package/dist/{ModelSettings-CKQ5CVAC.js → ModelSettings-G7IFNC2Y.js} +8 -6
- package/dist/{ModelSettings-CKQ5CVAC.js.map → ModelSettings-G7IFNC2Y.js.map} +1 -1
- package/dist/OpenUiFenceBlock-2TV5TQ6P.js +9 -0
- package/dist/OpenUiFenceBlock-2TV5TQ6P.js.map +1 -0
- package/dist/{SandboxSettings-HSCPYUOC.js → SandboxSettings-NXAANMAX.js} +8 -6
- package/dist/{SandboxSettings-HSCPYUOC.js.map → SandboxSettings-NXAANMAX.js.map} +1 -1
- package/dist/SchedulesPage-KKLUDO6B.js +15 -0
- package/dist/SchedulesPage-KKLUDO6B.js.map +1 -0
- package/dist/{SettingsBuilder-MYWRFXRI.js → SettingsBuilder-L34IQ56S.js} +26 -22
- package/dist/SettingsBuilder-L34IQ56S.js.map +1 -0
- package/dist/{ShellRouteSync-T4WLY57Q.js → ShellRouteSync-CEBETGEJ.js} +95 -22
- package/dist/ShellRouteSync-CEBETGEJ.js.map +1 -0
- package/dist/SidebarLayout-A2HJPPHS.js +308 -0
- package/dist/SidebarLayout-A2HJPPHS.js.map +1 -0
- package/dist/{SkillSettings-ECH6SHZ7.js → SkillSettings-FGGMSUNO.js} +8 -6
- package/dist/{SkillSettings-ECH6SHZ7.js.map → SkillSettings-FGGMSUNO.js.map} +1 -1
- package/dist/{TrueForgeUIWithRouter-KMHPOKLN.js → TrueForgeUIWithRouter-MZVJWJMB.js} +15 -11
- package/dist/{TrueForgeUIWithRouter-KMHPOKLN.js.map → TrueForgeUIWithRouter-MZVJWJMB.js.map} +1 -1
- package/dist/{WidgetLayout-4ZIG3RXV.js → WidgetLayout-6QM45OQQ.js} +19 -15
- package/dist/WidgetLayout-6QM45OQQ.js.map +1 -0
- package/dist/chunk-2XPPBEYF.js +74 -0
- package/dist/chunk-2XPPBEYF.js.map +1 -0
- package/dist/chunk-6O6FWUDW.js +1376 -0
- package/dist/chunk-6O6FWUDW.js.map +1 -0
- package/dist/chunk-7Z2C2K7F.js +578 -0
- package/dist/chunk-7Z2C2K7F.js.map +1 -0
- package/dist/{chunk-FXCYLEFB.js → chunk-BSIPI3KV.js} +18 -2
- package/dist/chunk-BSIPI3KV.js.map +1 -0
- package/dist/{chunk-255AE5NI.js → chunk-CYHJDKFB.js} +118 -33
- package/dist/chunk-CYHJDKFB.js.map +1 -0
- package/dist/chunk-DJUFS2BW.js +27 -0
- package/dist/chunk-DJUFS2BW.js.map +1 -0
- package/dist/chunk-DMMZSZTN.js +252 -0
- package/dist/chunk-DMMZSZTN.js.map +1 -0
- package/dist/chunk-FJW36PD7.js +180 -0
- package/dist/chunk-FJW36PD7.js.map +1 -0
- package/dist/chunk-M62XY4NC.js +555 -0
- package/dist/chunk-M62XY4NC.js.map +1 -0
- package/dist/{chunk-JRRCAKEP.js → chunk-MPNSO7E6.js} +2 -2
- package/dist/{chunk-CFLVPV5M.js → chunk-QC42MLAK.js} +7 -2
- package/dist/chunk-QC42MLAK.js.map +1 -0
- package/dist/chunk-RDXBMTP5.js +32 -0
- package/dist/chunk-RDXBMTP5.js.map +1 -0
- package/dist/chunk-SFZNIO6U.js +18 -0
- package/dist/chunk-SFZNIO6U.js.map +1 -0
- package/dist/chunk-U7KURWW3.js +840 -0
- package/dist/chunk-U7KURWW3.js.map +1 -0
- package/dist/chunk-WVE3F724.js +200 -0
- package/dist/chunk-WVE3F724.js.map +1 -0
- package/dist/{chunk-IFLE7OMM.js → chunk-XAU7QFG3.js} +180 -38
- package/dist/chunk-XAU7QFG3.js.map +1 -0
- package/dist/chunk-Y6S4OVVQ.js +16 -0
- package/dist/chunk-Y6S4OVVQ.js.map +1 -0
- package/dist/chunk-ZKNUMH2M.js +119 -0
- package/dist/chunk-ZKNUMH2M.js.map +1 -0
- package/dist/chunk-ZTMKFZQ3.js +13214 -0
- package/dist/chunk-ZTMKFZQ3.js.map +1 -0
- package/dist/{createTrueFoundryServer-B72bU-J7.d.ts → createTrueFoundryServer-CmZnBh_l.d.ts} +15 -4
- package/dist/index.d.ts +1199 -161
- package/dist/index.js +699 -69
- package/dist/index.js.map +1 -1
- package/dist/plugins/trueforge-agent-server-adapter/index.d.ts +552 -12
- package/dist/plugins/trueforge-agent-server-adapter/index.js +506 -188
- package/dist/plugins/trueforge-agent-server-adapter/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +11 -10
- package/dist/DrawerLayout-2JOQ4EDZ.js +0 -159
- package/dist/DrawerLayout-2JOQ4EDZ.js.map +0 -1
- package/dist/OpenUiFenceBlock-3EFPY4JW.js +0 -9
- package/dist/SettingsBuilder-MYWRFXRI.js.map +0 -1
- package/dist/ShellRouteSync-T4WLY57Q.js.map +0 -1
- package/dist/SidebarLayout-6MHQYW45.js +0 -239
- package/dist/SidebarLayout-6MHQYW45.js.map +0 -1
- package/dist/WidgetLayout-4ZIG3RXV.js.map +0 -1
- package/dist/chunk-255AE5NI.js.map +0 -1
- package/dist/chunk-72LC2M3R.js +0 -567
- package/dist/chunk-72LC2M3R.js.map +0 -1
- package/dist/chunk-CFLVPV5M.js.map +0 -1
- package/dist/chunk-FXCYLEFB.js.map +0 -1
- package/dist/chunk-IFLE7OMM.js.map +0 -1
- package/dist/chunk-IWPDSPVA.js +0 -2068
- package/dist/chunk-IWPDSPVA.js.map +0 -1
- package/dist/chunk-OZTNBS6V.js +0 -75
- package/dist/chunk-OZTNBS6V.js.map +0 -1
- package/dist/chunk-PUFYHFND.js +0 -91
- package/dist/chunk-PUFYHFND.js.map +0 -1
- package/dist/chunk-WQULF5AT.js +0 -460
- package/dist/chunk-WQULF5AT.js.map +0 -1
- package/dist/chunk-XRTTKGKN.js +0 -6825
- package/dist/chunk-XRTTKGKN.js.map +0 -1
- package/dist/chunk-YIWUG6MC.js +0 -101
- package/dist/chunk-YIWUG6MC.js.map +0 -1
- /package/dist/{OpenUiFenceBlock-3EFPY4JW.js.map → AgentMetricChart-JPU3MFQ2.js.map} +0 -0
- /package/dist/{chunk-JRRCAKEP.js.map → chunk-MPNSO7E6.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,90 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0-rc.1
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- d269b01: Add a live advanced agent configuration drawer with shared model, runtime, MCP tool, skill, and Save Agent editors.
|
|
8
|
+
- e74e953: Keep agent configuration visible on the left in full-width builder layouts, add a responsive instructions and initial-messages drawer with explicit save, make mobile config overlays closable, save the current instruction draft, align builder chrome, and preserve open widgets across chat runtime changes.
|
|
9
|
+
- a189482: Add routed agent detail pages with lazy Overview, Sessions, and Use In Code tabs backed by the optional AgentSessionsServer port and built-in TrueForge adapter.
|
|
10
|
+
- 8491843: Add a slot-driven agent Metrics tab with aggregate cards, time-range filtering, and Harness-backed line charts.
|
|
11
|
+
- a189482: Add the agent library Sessions tab and an all-user Sessions sidebar page (including drafts) with agent and time filters, shareable query params, and the same two-pane timeline. Library agent details keep the active tab in `?tab=` so opening an agent lands on Overview.
|
|
12
|
+
- bc11131: MCP selectors (composer + agent config) infinite-scroll through `listMcp` pages via DraftCatalogProvider.
|
|
13
|
+
- 860e322: Split New Chat vs New Agent: simple chat keeps the Connectors/Skills picker; New Agent keeps Agent Config + Save Agent. Session metadata `is_create_agent` drives resume from the sessions browser.
|
|
14
|
+
- 0cc59f8: Wire schedule test runs and show last five run status chips on the schedules table. Bump `@truefoundry/assistant-ui-runtime` to `0.1.25`.
|
|
15
|
+
- 0cc59f8: Add global Schedules page at `/schedules` with listing, popover-based filters, and create/edit drawer wired to the schedule API. New schedules save as paused, open a Test Schedule review with MCP connect status, and support Activate Anyway. List schedules uses server token pagination and multi-agent filters. Agents shows a Schedules count column (warning when any are paused) loaded via a batched list for on-screen agents. Add Table primitives with client-side and token pagination plus portal DropdownMenu so row actions are not clipped by overflow. Export a reusable popover select with single- and multi-select modes.
|
|
16
|
+
- 788636d: Sidebar layout is a permanent icon+label nav rail (no expand/collapse). Recent chats are hidden from the sidebar and mobile drawer; the drawer shows nav actions only.
|
|
17
|
+
- 8f1a2dc: Add a TrueFoundry-managed model registry. When `TRUEFOUNDRY_SERVICEFOUNDRY_SERVER_URL` is set, models are listed from the TrueFoundry ServiceFoundry server and turns are routed through the tenant's default AI Gateway with the caller's token. Mutually exclusive with OIDC. Supports internal mutual TLS to the ServiceFoundry server via `TRUEFOUNDRY_MTLS_ENABLED`/`TRUEFOUNDRY_MTLS_CERTS_DIR`.
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- 347a7e7: Refresh composer and composer-trigger styling: 0.75rem composer corners with a light-theme primary-token gradient hairline (faded top → solid bottom) and a neutral hairline in dark, an icon-only tools trigger in place of the "Tools" caption and count badge, the shared `agent-2` glyph on the agents-library trigger, and squared-off chrome-action geometry on the save-agent trigger. Also fixes `agent-2.svg` to use `currentColor` so it is legible in dark mode.
|
|
22
|
+
- a189482: Load agent Use In Code snippets through `client.internal.agents.getCodeSnippets` instead of a raw `client.fetch`.
|
|
23
|
+
- c4ee138: Agent list and details overflow menu: Edit, Clone (`{name}-copy` via saveAgent), Manage Schedules, and Delete (wired through harness `deleteAgent`).
|
|
24
|
+
- c4ee138: AgentSessions list pane uses a quieter surface, and the resize grip stays gray until hover, press, or focus.
|
|
25
|
+
- c4ee138: Agent Code (`SyntaxHighlighter` / `AgentCodeBlock`) copy control uses the bordered secondary button, and a trailing source newline no longer paints an empty last line while Copy still keeps the exact source.
|
|
26
|
+
- c4ee138: Agents, Sessions, and Schedules empty states use a shared centered empty-box screen with title and supporting copy.
|
|
27
|
+
- 0cc59f8: Use Google Sans as the default `trueforge` theme font and load it from Google Fonts when styles are injected.
|
|
28
|
+
- 64ca089: Hide Clear chat while the thread is fresh (New Chat, New Agent, and Try Agent) since there is nothing to clear.
|
|
29
|
+
- 64ca089: Add a book-icon preload toggle and dashed add button to Agent Config MCP server pills.
|
|
30
|
+
- d269b01: Improve MCP and skill selectors with consistent search sizing, explicit MCP selection controls, grouped tool summaries, and removable MCP chips.
|
|
31
|
+
- 64ca089: Revamp the MCP tools selector modal with focus rows, connect empty state, and grouped selected-tools summary.
|
|
32
|
+
- bc11131: New Chat enables sandbox on the live draft agent config when capabilities report sandbox as available.
|
|
33
|
+
- c4ee138: Resume Chat / Resume Agent building opens in a new tab when routed (`/sessions/:id` + square-arrow-out-up-right); without a router it keeps the in-shell resume fallback.
|
|
34
|
+
- 788636d: Open the create schedule drawer when Agents "+ Schedule" navigates with `isNew=true`, then clear the flag from the URL.
|
|
35
|
+
- 333230d: Improve Agent Sessions with a resizable divider, accurate turn grouping, optional cost display, and reliable timeline tooltips with sub-agent details. Simplify schedule recurrence and default new schedules to the local timezone.
|
|
36
|
+
- c4ee138: Unregister the `/settings` route when Settings chrome is unavailable (no catalog or `capabilities.settings.enabled` is false), matching the sidebar Settings button gate.
|
|
37
|
+
- c4ee138: Split New Chat and New Agent draft preference stores. New Chat remembers only model (+ reasoning), skills, and MCP; New Agent keeps the full seed including runtime config.
|
|
38
|
+
- 4c1260e: Wire TrueFoundry MCP authorize, status, and delete through ServiceFoundry; stub list auth_status; gate oauth2 invoke mid-turn with authRequired; paginate MCP server lists. UI treats SFY consent `code`/`error` on the FE landing like local DCR success/failure.
|
|
39
|
+
- c4ee138: Per-turn Tokens in Agent Sessions shows a keyboard-accessible Input / Output / Cached tooltip (Input is uncached).
|
|
40
|
+
- bc11131: Share a single `PageHeader` across chat and list chrome so title size/height stay consistent, and drop decorative title icons.
|
|
41
|
+
- Updated dependencies [648273b]
|
|
42
|
+
- Updated dependencies [648273b]
|
|
43
|
+
- Updated dependencies [2dcb3a0]
|
|
44
|
+
- Updated dependencies [52987a7]
|
|
45
|
+
- Updated dependencies [38ce068]
|
|
46
|
+
- Updated dependencies [b654052]
|
|
47
|
+
- Updated dependencies [4c1260e]
|
|
48
|
+
- Updated dependencies [f175245]
|
|
49
|
+
- @truefoundry/trueforge-sdk@0.1.4-rc.1
|
|
50
|
+
|
|
51
|
+
## 0.3.0-rc.0
|
|
52
|
+
|
|
53
|
+
### Minor Changes
|
|
54
|
+
|
|
55
|
+
- 3539da2: Add `brand.mode` (`icon-title` | `icon-only` | `logo`) so hosts pick chrome look first; `name` always labels the mark, and `resolveBrandChrome` maps mode to layout chrome.
|
|
56
|
+
- 16feb29: Add `customActionRenderers` so hosts can pause the composer on client-side tools with their own UI and resume via `onSubmit(content)`.
|
|
57
|
+
- 0297727: Add context-management compaction triggers with model-aware defaults and migrate persisted legacy token thresholds.
|
|
58
|
+
|
|
59
|
+
### Patch Changes
|
|
60
|
+
|
|
61
|
+
- b11cfc3: Wire remote chat session deletion and improve the history delete action styling.
|
|
62
|
+
- 3ca4e2e: fixed the button component icon and padding, delete conflicting local prettier.json in trueforge-ui package
|
|
63
|
+
- a655537: Update published dependency ranges (AI SDK, Hono, MCP SDK, Redis, assistant-ui, and related packages).
|
|
64
|
+
- aa4be44: Open markdown links in assistant messages in a new tab
|
|
65
|
+
- d7015fd: show mcp server tool name on tool approval
|
|
66
|
+
- Updated dependencies [648273b]
|
|
67
|
+
- @truefoundry/trueforge-sdk@0.1.4-rc.0
|
|
68
|
+
|
|
69
|
+
## Unreleased
|
|
70
|
+
|
|
71
|
+
### Minor Changes
|
|
72
|
+
|
|
73
|
+
- **`brand.mode`** — explicit chrome look. Set `mode`, then pass the fields it requires.
|
|
74
|
+
`name` always labels the mark (`alt` / `aria-label`):
|
|
75
|
+
- **`'icon-title'`** — `name` + optional `icon` (title shown in expanded chrome)
|
|
76
|
+
- **`'icon-only'`** — `name` + `icon` (alt kept, no title text)
|
|
77
|
+
- **`'logo'`** — `name` + `icon` + `logo` (wordmark in expanded chrome; `name` is alt only)
|
|
78
|
+
- **Default** — omit `brand` for the TrueForge wordmark / square mark
|
|
79
|
+
- **`resolveBrandChrome()`** — maps `brand.mode` to
|
|
80
|
+
`{ expandedVariant, collapsedVariant, showTitle }`. `SidebarLayout` uses it; custom
|
|
81
|
+
layouts should too.
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
|
|
85
|
+
- **`BrandConfig`** — discriminated on `mode` (`BrandMode`). Removed `showTitle` from
|
|
86
|
+
config; visible title follows the mode.
|
|
87
|
+
|
|
3
88
|
## 0.2.4
|
|
4
89
|
|
|
5
90
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -19,8 +19,6 @@ Powered by [assistant-ui](https://www.assistant-ui.com/), it follows the familia
|
|
|
19
19
|
|
|
20
20
|
Bring your own **brand, colors, layout, components, and server**—the Agent SDK wires up the rest.
|
|
21
21
|
|
|
22
|
-
### Checkout the Demo [here](./example/)
|
|
23
|
-
|
|
24
22
|
---
|
|
25
23
|
|
|
26
24
|
## Table of contents
|
|
@@ -209,7 +207,7 @@ export default function App() {
|
|
|
209
207
|
}}
|
|
210
208
|
theme={{
|
|
211
209
|
preset: 'claude',
|
|
212
|
-
brand: { name: 'Acme',
|
|
210
|
+
brand: { mode: 'icon-title', name: 'Acme', icon: '/icon.svg' },
|
|
213
211
|
}}
|
|
214
212
|
overrides={{/* slot overrides */}}
|
|
215
213
|
className="h-full"
|
|
@@ -321,7 +319,15 @@ package). Host CSS on `.aui-markdown` / `.aui-syntax-highlighter` / `.aui-openui
|
|
|
321
319
|
|
|
322
320
|
## Brand / logo
|
|
323
321
|
|
|
324
|
-
|
|
322
|
+
Set `brand.mode`, then pass the fields that mode requires. `name` always labels the
|
|
323
|
+
mark (`alt` / `aria-label`).
|
|
324
|
+
|
|
325
|
+
| Look | `mode` | Required | Expanded chrome | Collapsed / compact |
|
|
326
|
+
| ------------ | -------------- | -------------------------- | ------------------------- | ------------------- |
|
|
327
|
+
| Default | omit `brand` | — | TrueForge wordmark | TrueForge square |
|
|
328
|
+
| Icon + title | `'icon-title'` | `name` (+ optional `icon`) | square + title text | square |
|
|
329
|
+
| Icon only | `'icon-only'` | `name`, `icon` | square (no title text) | square |
|
|
330
|
+
| Wide logo | `'logo'` | `name`, `icon`, `logo` | wide logo (no title text) | square |
|
|
325
331
|
|
|
326
332
|
```tsx
|
|
327
333
|
<TrueForgeUI
|
|
@@ -329,15 +335,28 @@ package). Host CSS on `.aui-markdown` / `.aui-syntax-highlighter` / `.aui-openui
|
|
|
329
335
|
layout="sidebar"
|
|
330
336
|
theme={{
|
|
331
337
|
brand: {
|
|
338
|
+
mode: 'icon-title',
|
|
332
339
|
name: 'Acme',
|
|
333
|
-
|
|
340
|
+
icon: '/brand/icon.svg',
|
|
334
341
|
},
|
|
335
342
|
}}
|
|
336
343
|
/>
|
|
337
344
|
```
|
|
338
345
|
|
|
339
|
-
|
|
340
|
-
|
|
346
|
+
Icon-only chrome (`name` kept for alt):
|
|
347
|
+
|
|
348
|
+
```tsx
|
|
349
|
+
theme={{
|
|
350
|
+
brand: {
|
|
351
|
+
mode: 'icon-only',
|
|
352
|
+
name: 'Acme',
|
|
353
|
+
icon: '/brand/icon.svg',
|
|
354
|
+
},
|
|
355
|
+
}}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Wide logo for expanded chrome. A square `icon` is required because collapsed chrome,
|
|
359
|
+
the welcome screen, and the widget button continue to use the square asset:
|
|
341
360
|
|
|
342
361
|
```tsx
|
|
343
362
|
<TrueForgeUI
|
|
@@ -345,14 +364,19 @@ the resolved mode. `href` wraps the logo in a same-tab link:
|
|
|
345
364
|
layout="sidebar"
|
|
346
365
|
theme={{
|
|
347
366
|
brand: {
|
|
367
|
+
mode: 'logo',
|
|
348
368
|
name: 'Acme',
|
|
349
|
-
|
|
369
|
+
icon: '/brand/icon.svg',
|
|
370
|
+
logo: '/brand/wordmark.svg',
|
|
371
|
+
href: '/',
|
|
350
372
|
},
|
|
351
373
|
}}
|
|
352
374
|
/>
|
|
353
375
|
```
|
|
354
376
|
|
|
355
|
-
|
|
377
|
+
Both `icon` and `logo` accept `{ src, light, dark }`. The SDK picks the source matching the
|
|
378
|
+
resolved theme mode; setting only one light/dark source uses it for both. `href` wraps
|
|
379
|
+
configured images in a same-tab link.
|
|
356
380
|
|
|
357
381
|
**Component marks** — `theme.brand` takes image URLs only. To render an inline SVG or a custom
|
|
358
382
|
component, override the `BrandLogo` slot, the same way you replace any other atom:
|
|
@@ -361,7 +385,10 @@ component, override the `BrandLogo` slot, the same way you replace any other ato
|
|
|
361
385
|
<TrueForgeUI server={server} layout="sidebar" overrides={{ BrandLogo: MyMark }} />
|
|
362
386
|
```
|
|
363
387
|
|
|
364
|
-
**Custom layouts** — import `BrandLogo` and
|
|
388
|
+
**Custom layouts** — import `BrandLogo` and use `variant="icon"` for compact surfaces or
|
|
389
|
+
`variant="logo"` for expanded chrome. Prefer `resolveBrandChrome(useBrand())` so expanded
|
|
390
|
+
vs collapsed choices match the base layouts. Pair with `useBrandName()` when chrome should
|
|
391
|
+
show the title text (see [Custom layouts](#custom-layouts)).
|
|
365
392
|
|
|
366
393
|
> _Screenshot: external brand mark rendered in the base layout header._
|
|
367
394
|
|
|
@@ -373,12 +400,14 @@ component, override the `BrandLogo` slot, the same way you replace any other ato
|
|
|
373
400
|
|
|
374
401
|
| Mode | Layout chrome | Agent selection / New Chat |
|
|
375
402
|
| -------------------------------------- | ------------------------------- | --------------------------------------------------------- |
|
|
376
|
-
| `AgentLibraryWithComposer` _(default)_ | Agents
|
|
403
|
+
| `AgentLibraryWithComposer` _(default)_ | Agents + draft builder | New Chat opens draft; library picks a named agent |
|
|
377
404
|
| `SingleAgent` | Named-only, plain composer | Locked to `name`; New Chat / Clear Chat = new thread |
|
|
378
|
-
| `AgentLibrary` | Agents
|
|
405
|
+
| `AgentLibrary` | Agents only (no draft) | Empty until pick; no New Chat; Clear Chat after selection |
|
|
379
406
|
| `AgentComposer` | Draft builder only (no library) | Always draft; New Chat / Clear Chat = fresh draft |
|
|
380
407
|
|
|
381
|
-
In library modes, picking an agent from
|
|
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
|
+
|
|
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.
|
|
382
411
|
|
|
383
412
|
```tsx
|
|
384
413
|
{
|
|
@@ -409,7 +438,7 @@ In library modes, picking an agent from the Agents Library switches to a named c
|
|
|
409
438
|
/>;
|
|
410
439
|
```
|
|
411
440
|
|
|
412
|
-
> _Screenshot: Agents
|
|
441
|
+
> _Screenshot: Agents open; selecting an agent resets the thread._
|
|
413
442
|
|
|
414
443
|
---
|
|
415
444
|
|
|
@@ -424,8 +453,6 @@ Built-in `layout` values:
|
|
|
424
453
|
| `dock` | Fixed-width right panel; list XOR thread stack |
|
|
425
454
|
| `widget` | Same stack as `dock`, opened from a bottom-right FAB |
|
|
426
455
|
|
|
427
|
-
The [example app](./example/) switches between these four modes.
|
|
428
|
-
|
|
429
456
|
---
|
|
430
457
|
|
|
431
458
|
## Custom layouts
|
|
@@ -433,17 +460,15 @@ The [example app](./example/) switches between these four modes.
|
|
|
433
460
|
For full control, pass a React component as `layout`. The SDK still wires server, shell mode, slots, and runtime behind it.
|
|
434
461
|
|
|
435
462
|
```tsx
|
|
436
|
-
import { Thread, ThreadListContainer, BrandLogo,
|
|
463
|
+
import { Thread, ThreadListContainer, BrandLogo, useTheme } from '@truefoundry/trueforge-ui';
|
|
437
464
|
|
|
438
465
|
function Layout({ className }: { className?: string }) {
|
|
439
466
|
const { mode, setTheme } = useTheme();
|
|
440
|
-
const brandName = useBrandName();
|
|
441
467
|
|
|
442
468
|
return (
|
|
443
469
|
<div className={className} style={{ display: 'flex', height: '100%' }}>
|
|
444
470
|
<aside style={{ width: 256 }}>
|
|
445
|
-
<BrandLogo className="
|
|
446
|
-
<span>{brandName}</span>
|
|
471
|
+
<BrandLogo variant="logo" className="h-6 w-auto max-w-40" />
|
|
447
472
|
<ThreadListContainer />
|
|
448
473
|
</aside>
|
|
449
474
|
<main style={{ flex: 1, minWidth: 0 }}>
|
|
@@ -492,7 +517,7 @@ function MyBubble({ children, error, actionBar, className }: AssistantMessageBub
|
|
|
492
517
|
/>;
|
|
493
518
|
```
|
|
494
519
|
|
|
495
|
-
Overridable slots include composer pieces (`ComposerShell`, `ComposerLeftSection`, `ComposerRightSection`, `ComposerSendButton`), messages (`AssistantMessageBubble`, `UserMessageBubble`, `UserMessageEdit`), `Markdown`, `WelcomeScreen`, thread-list atoms, and tool/prompt cards (`ToolCallCard`, `ToolApprovalBar`, `ToolGroupCard`, `SubAgentCard`, `SandboxToolCallCard`, `AgentStepsCard`, `ReasoningCard`, `AskUserPrompt`, `McpAuthPrompt`, and more).
|
|
520
|
+
Overridable slots include composer pieces (`ComposerShell`, `ComposerLeftSection`, `ComposerRightSection`, `ComposerSendButton`), messages (`AssistantMessageBubble`, `UserMessageBubble`, `UserMessageEdit`), `Markdown`, `WelcomeScreen`, thread-list atoms, agent metrics (`AgentMetrics`, `AgentMetricsView`, `AgentMetricsTimeRangeFilter`, `AgentMetricCard`, `AgentMetricChart`), and tool/prompt cards (`ToolCallCard`, `ToolApprovalBar`, `ToolGroupCard`, `SubAgentCard`, `SandboxToolCallCard`, `AgentStepsCard`, `ReasoningCard`, `AskUserPrompt`, `McpAuthPrompt`, and more).
|
|
496
521
|
|
|
497
522
|
See [docs/customization.md](./docs/customization.md) for the full slot list.
|
|
498
523
|
|
|
@@ -520,13 +545,19 @@ type TrueForgeServerConfig =
|
|
|
520
545
|
}
|
|
521
546
|
| AgentUIServer;
|
|
522
547
|
|
|
523
|
-
type AgentUIServer = AgentChatServer &
|
|
548
|
+
type AgentUIServer = AgentChatServer &
|
|
549
|
+
AgentBuilderServer & {
|
|
550
|
+
catalog?: CatalogServer;
|
|
551
|
+
sessions?: AgentSessionsServer;
|
|
552
|
+
metrics?: AgentMetricsServer;
|
|
553
|
+
};
|
|
524
554
|
```
|
|
525
555
|
|
|
526
556
|
| Port | Responsibility |
|
|
527
557
|
| -------------------- | ------------------------------------------------------------------- |
|
|
528
558
|
| `AgentChatServer` | Sessions, turns, streaming, draft `AgentSpec` sync |
|
|
529
559
|
| `AgentBuilderServer` | `getModels` / `getSkills` / `getMcp` / `searchAgents` / `saveAgent` |
|
|
560
|
+
| `AgentMetricsServer` | Agent meter aggregates, chart definitions, and chart data |
|
|
530
561
|
|
|
531
562
|
**Zero-config TrueFoundry** — see [Getting started](#getting-started). The SDK calls `createTrueFoundryAgentUIServer` for you.
|
|
532
563
|
|
|
@@ -591,6 +622,7 @@ See [docs/server.md](./docs/server.md) for the full method list and BYO guidance
|
|
|
591
622
|
| `TrueForgeServerConfig` | Type | `server` prop: `truefoundry` / `trueforge` / `AgentUIServer` |
|
|
592
623
|
| `createTrueFoundryServer` | Function | Compose chat + builder into `AgentUIServer` |
|
|
593
624
|
| `Thread`, `ThreadListContainer`, `BrandLogo` | Components | Layout primitives for custom layouts |
|
|
625
|
+
| `resolveBrandChrome`, `useBrandName`, `useBrand` | Helpers | Brand chrome look + name for custom layouts |
|
|
594
626
|
| Composer / message / tool atoms | Components | Overridable, themeable building blocks |
|
|
595
627
|
| `SlotsProvider`, `useSlot`, `useTheme` | API | Overrides + theme mode |
|
|
596
628
|
| `AgentUIServer`, `AgentChatServer`, `AgentBuilderServer` | Types | Resolved server contract |
|
|
@@ -630,7 +662,7 @@ pnpm --filter @truefoundry/trueforge-ui test
|
|
|
630
662
|
pnpm --filter @truefoundry/trueforge-ui build
|
|
631
663
|
```
|
|
632
664
|
|
|
633
|
-
|
|
665
|
+
Publishing: see [RELEASING.md](../../RELEASING.md#releasing-truefoundrytrueforge-ui).
|
|
634
666
|
|
|
635
667
|
---
|
|
636
668
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
useSlot
|
|
4
|
+
} from "./chunk-ZTMKFZQ3.js";
|
|
5
|
+
import "./chunk-2XPPBEYF.js";
|
|
6
|
+
import {
|
|
7
|
+
Icon
|
|
8
|
+
} from "./chunk-XAU7QFG3.js";
|
|
9
|
+
import "./chunk-U7KURWW3.js";
|
|
10
|
+
import "./chunk-M6MHLVSO.js";
|
|
11
|
+
import "./chunk-MPNSO7E6.js";
|
|
12
|
+
import {
|
|
13
|
+
cn
|
|
14
|
+
} from "./chunk-7Z2C2K7F.js";
|
|
15
|
+
|
|
16
|
+
// src/atoms/agent-details/AgentCodeSnippets.tsx
|
|
17
|
+
import { useEffect, useState } from "react";
|
|
18
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
+
function AgentCodeSnippets({ snippets }) {
|
|
20
|
+
const AgentCodeBlock = useSlot("AgentCodeBlock");
|
|
21
|
+
const [selectedLanguage, setSelectedLanguage] = useState(snippets[0]?.language);
|
|
22
|
+
const [mode, setMode] = useState("stream");
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
setSelectedLanguage(snippets[0]?.language);
|
|
25
|
+
setMode("stream");
|
|
26
|
+
}, [snippets]);
|
|
27
|
+
const selected = snippets.find((snippet) => snippet.language === selectedLanguage) ?? snippets[0];
|
|
28
|
+
if (selected === void 0) {
|
|
29
|
+
return /* @__PURE__ */ jsx("div", { className: "flex h-full min-h-64 items-center justify-center px-6 text-sm text-text-secondary", children: "No code samples for this agent." });
|
|
30
|
+
}
|
|
31
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-3 p-3 md:flex-row", children: [
|
|
32
|
+
/* @__PURE__ */ jsx("nav", { "aria-label": "Code sample languages", className: "flex shrink-0 gap-1 overflow-auto md:w-44 md:flex-col", children: snippets.map((snippet) => /* @__PURE__ */ jsxs(
|
|
33
|
+
"button",
|
|
34
|
+
{
|
|
35
|
+
type: "button",
|
|
36
|
+
"aria-current": selected.language === snippet.language ? "page" : void 0,
|
|
37
|
+
className: cn(
|
|
38
|
+
"flex h-9 shrink-0 cursor-pointer items-center gap-2 rounded-md px-2.5 text-left text-xs text-text-secondary",
|
|
39
|
+
"hover:bg-ghost-button-hover hover:text-text-primary",
|
|
40
|
+
selected.language === snippet.language && "bg-primary-button-bg/10 font-medium text-primary-button-bg"
|
|
41
|
+
),
|
|
42
|
+
onClick: () => setSelectedLanguage(snippet.language),
|
|
43
|
+
children: [
|
|
44
|
+
snippet.icon ? /* @__PURE__ */ jsx("img", { src: snippet.icon, alt: "", className: "size-4 shrink-0 object-contain" }) : /* @__PURE__ */ jsx(Icon, { name: "code", className: "size-4 shrink-0" }),
|
|
45
|
+
snippet.labelName
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
snippet.language
|
|
49
|
+
)) }),
|
|
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
|
+
)) }),
|
|
67
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto", children: /* @__PURE__ */ jsx(AgentCodeBlock, { code: selected.sampleCode[mode], language: selected.language }) })
|
|
68
|
+
] })
|
|
69
|
+
] });
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
AgentCodeSnippets as default
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=AgentCodeSnippets-NZOFJE57.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-end gap-1 border-b border-border px-3\">\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 <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,0BAAC,SAAI,WAAU,kEAEX;AAAA,QACE,CAAC,UAAU,QAAQ;AAAA,QACnB,CAAC,aAAa,YAAY;AAAA,MAC5B,EACA,IAAI,CAAC,CAAC,IAAI,KAAK,MACf;AAAA,QAAC;AAAA;AAAA,UAEC,MAAK;AAAA,UACL,WAAW;AAAA,YACT;AAAA,YACA,SAAS,MACP;AAAA,UACJ;AAAA,UACA,SAAS,MAAM,QAAQ,EAAE;AAAA,UAExB;AAAA;AAAA,QATI;AAAA,MAUP,CACD,GACH;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-ZKNUMH2M.js";
|
|
5
|
+
import "./chunk-ZTMKFZQ3.js";
|
|
6
|
+
import "./chunk-2XPPBEYF.js";
|
|
7
|
+
import "./chunk-XAU7QFG3.js";
|
|
8
|
+
import "./chunk-U7KURWW3.js";
|
|
9
|
+
import "./chunk-M6MHLVSO.js";
|
|
10
|
+
import "./chunk-MPNSO7E6.js";
|
|
11
|
+
import "./chunk-7Z2C2K7F.js";
|
|
12
|
+
export {
|
|
13
|
+
AgentMetricChart
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=AgentMetricChart-JPU3MFQ2.js.map
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
useSlot
|
|
4
|
+
} from "./chunk-ZTMKFZQ3.js";
|
|
5
|
+
import "./chunk-2XPPBEYF.js";
|
|
6
|
+
import {
|
|
7
|
+
Icon
|
|
8
|
+
} from "./chunk-XAU7QFG3.js";
|
|
9
|
+
import "./chunk-U7KURWW3.js";
|
|
10
|
+
import "./chunk-M6MHLVSO.js";
|
|
11
|
+
import "./chunk-MPNSO7E6.js";
|
|
12
|
+
import {
|
|
13
|
+
cn
|
|
14
|
+
} from "./chunk-7Z2C2K7F.js";
|
|
15
|
+
|
|
16
|
+
// src/atoms/agent-details/AgentOverview.tsx
|
|
17
|
+
import { useState } from "react";
|
|
18
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
+
var valueClassName = "text-right font-mono text-primary-button-bg";
|
|
20
|
+
function isRecord(value) {
|
|
21
|
+
return typeof value === "object" && value != null;
|
|
22
|
+
}
|
|
23
|
+
function readName(value) {
|
|
24
|
+
if (!("name" in value) || typeof value.name !== "string") return null;
|
|
25
|
+
return value.name;
|
|
26
|
+
}
|
|
27
|
+
function readRecordValue(record, ...keys) {
|
|
28
|
+
for (const key of keys) {
|
|
29
|
+
const value = record?.[key];
|
|
30
|
+
if (value !== void 0) return value;
|
|
31
|
+
}
|
|
32
|
+
return void 0;
|
|
33
|
+
}
|
|
34
|
+
function hasAllTools(value) {
|
|
35
|
+
if (!isRecord(value)) return false;
|
|
36
|
+
const tools = readRecordValue(value, "enableTools", "enable_tools");
|
|
37
|
+
return tools === void 0 || Array.isArray(tools) && tools.includes("@all");
|
|
38
|
+
}
|
|
39
|
+
function displayModelName(name) {
|
|
40
|
+
const slash = name.lastIndexOf("/");
|
|
41
|
+
return slash >= 0 ? name.slice(slash + 1) : name;
|
|
42
|
+
}
|
|
43
|
+
function AgentOverview({ detail }) {
|
|
44
|
+
const Markdown = useSlot("Markdown");
|
|
45
|
+
const AgentOverviewCard = useSlot("AgentOverviewCard");
|
|
46
|
+
const [instructionsView, setInstructionsView] = useState("markdown");
|
|
47
|
+
const [copied, setCopied] = useState(false);
|
|
48
|
+
const spec = detail.agentSpec;
|
|
49
|
+
const skills = spec.skills ?? [];
|
|
50
|
+
const connectors = spec.mcpServers ?? [];
|
|
51
|
+
const modelParams = isRecord(spec.model.params) ? spec.model.params : null;
|
|
52
|
+
const maxTokens = readRecordValue(modelParams, "maxTokens", "max_tokens");
|
|
53
|
+
const temperature = readRecordValue(modelParams, "temperature");
|
|
54
|
+
const config = isRecord(spec.config) ? spec.config : null;
|
|
55
|
+
const sandbox = isRecord(config?.sandbox) ? config.sandbox : null;
|
|
56
|
+
const instructions = spec.instructions?.trim() ? spec.instructions : null;
|
|
57
|
+
const execution = [
|
|
58
|
+
["Sandbox", typeof sandbox?.enabled === "boolean" ? sandbox.enabled ? "Enabled" : "Disabled" : void 0],
|
|
59
|
+
["Iteration limit", readRecordValue(config, "iterationLimit", "iteration_limit")],
|
|
60
|
+
["Response format", readRecordValue(config, "responseFormat", "response_format")]
|
|
61
|
+
].filter((entry) => {
|
|
62
|
+
return typeof entry[1] === "string" || typeof entry[1] === "number";
|
|
63
|
+
});
|
|
64
|
+
const capabilities = [
|
|
65
|
+
["Generative UI", spec.config?.generativeUi?.enabled],
|
|
66
|
+
["Dynamic sub-agents", spec.config?.dynamicSubAgents?.enabled],
|
|
67
|
+
["Ask user questions", spec.config?.askUserQuestions?.enabled]
|
|
68
|
+
].filter((entry) => typeof entry[1] === "boolean");
|
|
69
|
+
const toggleLabel = instructionsView === "markdown" ? "Raw" : "Markdown";
|
|
70
|
+
return /* @__PURE__ */ jsxs("div", { className: "grid min-h-0 flex-1 gap-3 overflow-auto p-4 md:grid-cols-[minmax(0,1fr)_18rem] md:overflow-hidden", children: [
|
|
71
|
+
/* @__PURE__ */ jsxs("section", { className: "flex min-h-64 flex-col rounded-lg border border-border bg-card-bg p-4 text-text-primary", children: [
|
|
72
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-3 flex shrink-0 items-center justify-between gap-2", children: [
|
|
73
|
+
/* @__PURE__ */ jsxs("h2", { className: "flex items-center gap-1.5 text-sm font-semibold text-text-primary", children: [
|
|
74
|
+
/* @__PURE__ */ jsx(Icon, { name: "book-open", className: "size-4 text-text-secondary" }),
|
|
75
|
+
"Instructions"
|
|
76
|
+
] }),
|
|
77
|
+
instructions ? /* @__PURE__ */ jsxs(
|
|
78
|
+
"div",
|
|
79
|
+
{
|
|
80
|
+
className: "inline-flex h-7 items-stretch overflow-hidden rounded-md border border-border bg-primary-bg text-xs font-medium text-text-secondary",
|
|
81
|
+
role: "group",
|
|
82
|
+
"aria-label": "Instructions actions",
|
|
83
|
+
children: [
|
|
84
|
+
/* @__PURE__ */ jsx(
|
|
85
|
+
"button",
|
|
86
|
+
{
|
|
87
|
+
type: "button",
|
|
88
|
+
"aria-label": `Show ${toggleLabel}`,
|
|
89
|
+
onClick: () => setInstructionsView((view) => view === "markdown" ? "raw" : "markdown"),
|
|
90
|
+
className: "cursor-pointer px-2.5 transition-colors hover:bg-ghost-button-hover hover:text-text-primary",
|
|
91
|
+
children: toggleLabel
|
|
92
|
+
}
|
|
93
|
+
),
|
|
94
|
+
/* @__PURE__ */ jsx("span", { className: "w-px self-stretch bg-border", "aria-hidden": true }),
|
|
95
|
+
/* @__PURE__ */ jsx(
|
|
96
|
+
"button",
|
|
97
|
+
{
|
|
98
|
+
type: "button",
|
|
99
|
+
title: copied ? "Copied!" : "Copy",
|
|
100
|
+
"aria-label": copied ? "Copied!" : "Copy",
|
|
101
|
+
onClick: () => {
|
|
102
|
+
void navigator.clipboard.writeText(instructions).then(() => {
|
|
103
|
+
setCopied(true);
|
|
104
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
className: "inline-flex cursor-pointer items-center justify-center px-2 transition-colors hover:bg-ghost-button-hover hover:text-text-primary",
|
|
108
|
+
children: /* @__PURE__ */ jsx(Icon, { name: copied ? "check" : "copy", size: 12 })
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
) : null
|
|
114
|
+
] }),
|
|
115
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto", children: instructions ? instructionsView === "markdown" ? /* @__PURE__ */ jsx(Markdown, { content: instructions, readOnly: true, className: "text-sm" }) : /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap break-words font-mono text-sm text-text-primary", children: instructions }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-text-secondary", children: "No instructions for this agent." }) })
|
|
116
|
+
] }),
|
|
117
|
+
/* @__PURE__ */ jsxs("aside", { className: "flex min-h-0 min-w-0 flex-col gap-3 md:overflow-auto", children: [
|
|
118
|
+
/* @__PURE__ */ jsx(AgentOverviewCard, { title: "Model Configuration", icon: "cpu", children: /* @__PURE__ */ jsxs("dl", { className: "grid grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1 text-xs", children: [
|
|
119
|
+
/* @__PURE__ */ jsx("dt", { className: "text-text-secondary", children: "Model" }),
|
|
120
|
+
/* @__PURE__ */ jsx("dd", { className: cn(valueClassName, "truncate"), title: spec.model.name, children: displayModelName(spec.model.name) }),
|
|
121
|
+
typeof maxTokens === "number" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
122
|
+
/* @__PURE__ */ jsx("dt", { className: "text-text-secondary", children: "Max tokens" }),
|
|
123
|
+
/* @__PURE__ */ jsx("dd", { className: valueClassName, children: maxTokens })
|
|
124
|
+
] }) : null,
|
|
125
|
+
spec.model.params?.reasoningEffort !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
126
|
+
/* @__PURE__ */ jsx("dt", { className: "text-text-secondary", children: "Reasoning" }),
|
|
127
|
+
/* @__PURE__ */ jsx("dd", { className: valueClassName, children: spec.model.params.reasoningEffort })
|
|
128
|
+
] }) : null,
|
|
129
|
+
typeof temperature === "number" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
130
|
+
/* @__PURE__ */ jsx("dt", { className: "text-text-secondary", children: "Temperature" }),
|
|
131
|
+
/* @__PURE__ */ jsx("dd", { className: valueClassName, children: temperature })
|
|
132
|
+
] }) : null
|
|
133
|
+
] }) }),
|
|
134
|
+
/* @__PURE__ */ jsx(AgentOverviewCard, { title: "MCP Servers", icon: "plug", count: connectors.length, children: connectors.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-xs text-text-secondary", children: "No connectors attached." }) : /* @__PURE__ */ jsx("ul", { className: "space-y-1.5", children: connectors.map((connector, index) => /* @__PURE__ */ jsx(
|
|
135
|
+
"li",
|
|
136
|
+
{
|
|
137
|
+
className: "rounded-md bg-secondary-bg px-2 py-1.5 text-xs",
|
|
138
|
+
children: /* @__PURE__ */ jsxs("span", { className: "flex items-center justify-between gap-2", children: [
|
|
139
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: readName(connector) ?? `Connector ${index + 1}` }),
|
|
140
|
+
hasAllTools(connector) ? /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full bg-primary-button-bg/10 px-1.5 py-0.5 text-[10px] text-primary-button-bg", children: "All tools" }) : null
|
|
141
|
+
] })
|
|
142
|
+
},
|
|
143
|
+
`${readName(connector) ?? "connector"}-${index}`
|
|
144
|
+
)) }) }),
|
|
145
|
+
/* @__PURE__ */ jsx(AgentOverviewCard, { title: "Attached Skills", icon: "lightbulb", count: skills.length, children: skills.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-xs text-text-secondary", children: "No skills attached." }) : /* @__PURE__ */ jsx("ul", { className: "space-y-1.5", children: skills.map((skill, index) => /* @__PURE__ */ jsx(
|
|
146
|
+
"li",
|
|
147
|
+
{
|
|
148
|
+
className: "rounded-md bg-secondary-bg px-2 py-1.5 text-xs",
|
|
149
|
+
children: readName(skill) ?? `Skill ${index + 1}`
|
|
150
|
+
},
|
|
151
|
+
`${readName(skill) ?? "skill"}-${index}`
|
|
152
|
+
)) }) }),
|
|
153
|
+
execution.length > 0 ? /* @__PURE__ */ jsx(AgentOverviewCard, { title: "Execution", icon: "terminal", children: /* @__PURE__ */ jsx("dl", { className: "space-y-1 text-xs", children: execution.map(([label, value]) => /* @__PURE__ */ jsxs("div", { className: "flex justify-between gap-3", children: [
|
|
154
|
+
/* @__PURE__ */ jsx("dt", { className: "text-text-secondary", children: label }),
|
|
155
|
+
/* @__PURE__ */ jsx("dd", { className: valueClassName, children: value })
|
|
156
|
+
] }, label)) }) }) : null,
|
|
157
|
+
capabilities.length > 0 ? /* @__PURE__ */ jsx(AgentOverviewCard, { title: "Capabilities", icon: "cube", children: /* @__PURE__ */ jsx("dl", { className: "space-y-1 text-xs", children: capabilities.map(([label, enabled]) => /* @__PURE__ */ jsxs("div", { className: "flex justify-between gap-3", children: [
|
|
158
|
+
/* @__PURE__ */ jsx("dt", { className: "text-text-secondary", children: label }),
|
|
159
|
+
/* @__PURE__ */ jsx("dd", { className: valueClassName, children: enabled ? "Enabled" : "Disabled" })
|
|
160
|
+
] }, label)) }) }) : null
|
|
161
|
+
] })
|
|
162
|
+
] });
|
|
163
|
+
}
|
|
164
|
+
export {
|
|
165
|
+
AgentOverview as default
|
|
166
|
+
};
|
|
167
|
+
//# sourceMappingURL=AgentOverview-EEBHJC32.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/atoms/agent-details/AgentOverview.tsx"],"sourcesContent":["'use client';\n\nimport { 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 { AgentOverviewProps } from './types.js';\n\ntype InstructionsView = 'markdown' | 'raw';\n\nconst valueClassName = 'text-right font-mono text-primary-button-bg';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value != null;\n}\n\nfunction readName(value: object): string | null {\n if (!('name' in value) || typeof value.name !== 'string') return null;\n return value.name;\n}\n\nfunction readRecordValue(record: Record<string, unknown> | null, ...keys: string[]): unknown {\n for (const key of keys) {\n const value = record?.[key];\n if (value !== undefined) return value;\n }\n return undefined;\n}\n\nfunction hasAllTools(value: object): boolean {\n if (!isRecord(value)) return false;\n const tools = readRecordValue(value, 'enableTools', 'enable_tools');\n return tools === undefined || (Array.isArray(tools) && tools.includes('@all'));\n}\n\nfunction displayModelName(name: string): string {\n const slash = name.lastIndexOf('/');\n return slash >= 0 ? name.slice(slash + 1) : name;\n}\n\nexport default function AgentOverview({ detail }: AgentOverviewProps) {\n const Markdown = useSlot('Markdown');\n const AgentOverviewCard = useSlot('AgentOverviewCard');\n const [instructionsView, setInstructionsView] = useState<InstructionsView>('markdown');\n const [copied, setCopied] = useState(false);\n const spec = detail.agentSpec;\n const skills = spec.skills ?? [];\n const connectors = spec.mcpServers ?? [];\n const modelParams = isRecord(spec.model.params) ? spec.model.params : null;\n const maxTokens = readRecordValue(modelParams, 'maxTokens', 'max_tokens');\n const temperature = readRecordValue(modelParams, 'temperature');\n const config = isRecord(spec.config) ? spec.config : null;\n const sandbox = isRecord(config?.sandbox) ? config.sandbox : null;\n const instructions = spec.instructions?.trim() ? spec.instructions : null;\n const execution = [\n ['Sandbox', typeof sandbox?.enabled === 'boolean' ? (sandbox.enabled ? 'Enabled' : 'Disabled') : undefined],\n ['Iteration limit', readRecordValue(config, 'iterationLimit', 'iteration_limit')],\n ['Response format', readRecordValue(config, 'responseFormat', 'response_format')],\n ].filter((entry): entry is [string, string | number] => {\n return typeof entry[1] === 'string' || typeof entry[1] === 'number';\n });\n const capabilities = [\n ['Generative UI', spec.config?.generativeUi?.enabled],\n ['Dynamic sub-agents', spec.config?.dynamicSubAgents?.enabled],\n ['Ask user questions', spec.config?.askUserQuestions?.enabled],\n ].filter((entry): entry is [string, boolean] => typeof entry[1] === 'boolean');\n const toggleLabel = instructionsView === 'markdown' ? 'Raw' : 'Markdown';\n\n return (\n <div className=\"grid min-h-0 flex-1 gap-3 overflow-auto p-4 md:grid-cols-[minmax(0,1fr)_18rem] md:overflow-hidden\">\n <section className=\"flex min-h-64 flex-col rounded-lg border border-border bg-card-bg p-4 text-text-primary\">\n <div className=\"mb-3 flex shrink-0 items-center justify-between gap-2\">\n <h2 className=\"flex items-center gap-1.5 text-sm font-semibold text-text-primary\">\n <Icon name=\"book-open\" className=\"size-4 text-text-secondary\" />\n Instructions\n </h2>\n {instructions ? (\n <div\n className=\"inline-flex h-7 items-stretch overflow-hidden rounded-md border border-border bg-primary-bg text-xs font-medium text-text-secondary\"\n role=\"group\"\n aria-label=\"Instructions actions\"\n >\n <button\n type=\"button\"\n aria-label={`Show ${toggleLabel}`}\n onClick={() => setInstructionsView(view => (view === 'markdown' ? 'raw' : 'markdown'))}\n className=\"cursor-pointer px-2.5 transition-colors hover:bg-ghost-button-hover hover:text-text-primary\"\n >\n {toggleLabel}\n </button>\n <span className=\"w-px self-stretch bg-border\" aria-hidden />\n <button\n type=\"button\"\n title={copied ? 'Copied!' : 'Copy'}\n aria-label={copied ? 'Copied!' : 'Copy'}\n onClick={() => {\n void navigator.clipboard.writeText(instructions).then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n });\n }}\n className=\"inline-flex cursor-pointer items-center justify-center px-2 transition-colors hover:bg-ghost-button-hover hover:text-text-primary\"\n >\n <Icon name={copied ? 'check' : 'copy'} size={12} />\n </button>\n </div>\n ) : null}\n </div>\n <div className=\"min-h-0 flex-1 overflow-auto\">\n {instructions ? (\n instructionsView === 'markdown' ? (\n <Markdown content={instructions} readOnly className=\"text-sm\" />\n ) : (\n <pre className=\"whitespace-pre-wrap break-words font-mono text-sm text-text-primary\">{instructions}</pre>\n )\n ) : (\n <p className=\"text-sm text-text-secondary\">No instructions for this agent.</p>\n )}\n </div>\n </section>\n\n <aside className=\"flex min-h-0 min-w-0 flex-col gap-3 md:overflow-auto\">\n <AgentOverviewCard title=\"Model Configuration\" icon=\"cpu\">\n <dl className=\"grid grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1 text-xs\">\n <dt className=\"text-text-secondary\">Model</dt>\n <dd className={cn(valueClassName, 'truncate')} title={spec.model.name}>\n {displayModelName(spec.model.name)}\n </dd>\n {typeof maxTokens === 'number' ? (\n <>\n <dt className=\"text-text-secondary\">Max tokens</dt>\n <dd className={valueClassName}>{maxTokens}</dd>\n </>\n ) : null}\n {spec.model.params?.reasoningEffort !== undefined ? (\n <>\n <dt className=\"text-text-secondary\">Reasoning</dt>\n <dd className={valueClassName}>{spec.model.params.reasoningEffort}</dd>\n </>\n ) : null}\n {typeof temperature === 'number' ? (\n <>\n <dt className=\"text-text-secondary\">Temperature</dt>\n <dd className={valueClassName}>{temperature}</dd>\n </>\n ) : null}\n </dl>\n </AgentOverviewCard>\n <AgentOverviewCard title=\"MCP Servers\" icon=\"plug\" count={connectors.length}>\n {connectors.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">No connectors attached.</p>\n ) : (\n <ul className=\"space-y-1.5\">\n {connectors.map((connector, index) => (\n <li\n key={`${readName(connector) ?? 'connector'}-${index}`}\n className=\"rounded-md bg-secondary-bg px-2 py-1.5 text-xs\"\n >\n <span className=\"flex items-center justify-between gap-2\">\n <span className=\"truncate\">{readName(connector) ?? `Connector ${index + 1}`}</span>\n {hasAllTools(connector) ? (\n <span className=\"shrink-0 rounded-full bg-primary-button-bg/10 px-1.5 py-0.5 text-[10px] text-primary-button-bg\">\n All tools\n </span>\n ) : null}\n </span>\n </li>\n ))}\n </ul>\n )}\n </AgentOverviewCard>\n\n <AgentOverviewCard title=\"Attached Skills\" icon=\"lightbulb\" count={skills.length}>\n {skills.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">No skills attached.</p>\n ) : (\n <ul className=\"space-y-1.5\">\n {skills.map((skill, index) => (\n <li\n key={`${readName(skill) ?? 'skill'}-${index}`}\n className=\"rounded-md bg-secondary-bg px-2 py-1.5 text-xs\"\n >\n {readName(skill) ?? `Skill ${index + 1}`}\n </li>\n ))}\n </ul>\n )}\n </AgentOverviewCard>\n\n {execution.length > 0 ? (\n <AgentOverviewCard title=\"Execution\" icon=\"terminal\">\n <dl className=\"space-y-1 text-xs\">\n {execution.map(([label, value]) => (\n <div key={label} className=\"flex justify-between gap-3\">\n <dt className=\"text-text-secondary\">{label}</dt>\n <dd className={valueClassName}>{value}</dd>\n </div>\n ))}\n </dl>\n </AgentOverviewCard>\n ) : null}\n\n {capabilities.length > 0 ? (\n <AgentOverviewCard title=\"Capabilities\" icon=\"cube\">\n <dl className=\"space-y-1 text-xs\">\n {capabilities.map(([label, enabled]) => (\n <div key={label} className=\"flex justify-between gap-3\">\n <dt className=\"text-text-secondary\">{label}</dt>\n <dd className={valueClassName}>{enabled ? 'Enabled' : 'Disabled'}</dd>\n </div>\n ))}\n </dl>\n </AgentOverviewCard>\n ) : null}\n </aside>\n </div>\n );\n}\n\ndeclare module '../../theme/SlotsProvider.js' {\n interface AtomSlots {\n AgentOverview: ComponentType<AgentOverviewProps>;\n }\n}\n"],"mappings":"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","names":[]}
|