@truefoundry/trueforge-ui 0.0.0 → 0.1.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 +348 -0
- package/LICENSE +21 -0
- package/NOTICE +17 -0
- package/README.md +640 -3
- package/dist/ConnectorSettings-ADACLWQI.js +898 -0
- package/dist/ConnectorSettings-ADACLWQI.js.map +1 -0
- package/dist/DockLayout-BH5XX2AQ.js +35 -0
- package/dist/DockLayout-BH5XX2AQ.js.map +1 -0
- package/dist/DrawerLayout-O2XZQCG4.js +156 -0
- package/dist/DrawerLayout-O2XZQCG4.js.map +1 -0
- package/dist/ModelSettings-LKFJVUYQ.js +1082 -0
- package/dist/ModelSettings-LKFJVUYQ.js.map +1 -0
- package/dist/OpenUiFenceBlock-A2CWCPOP.js +9 -0
- package/dist/OpenUiFenceBlock-A2CWCPOP.js.map +1 -0
- package/dist/SandboxSettings-H5MDAE47.js +505 -0
- package/dist/SandboxSettings-H5MDAE47.js.map +1 -0
- package/dist/SettingsBuilder-3JOLC56Z.js +136 -0
- package/dist/SettingsBuilder-3JOLC56Z.js.map +1 -0
- package/dist/SidebarLayout-G6BGD7EY.js +236 -0
- package/dist/SidebarLayout-G6BGD7EY.js.map +1 -0
- package/dist/SkillSettings-4VB42CVG.js +389 -0
- package/dist/SkillSettings-4VB42CVG.js.map +1 -0
- package/dist/WidgetLayout-ABSXZUSQ.js +101 -0
- package/dist/WidgetLayout-ABSXZUSQ.js.map +1 -0
- package/dist/assistant-ui.d.ts +1 -0
- package/dist/assistant-ui.js +9 -0
- package/dist/assistant-ui.js.map +1 -0
- package/dist/chunk-3PTFNAQK.js +2088 -0
- package/dist/chunk-3PTFNAQK.js.map +1 -0
- package/dist/chunk-CFLVPV5M.js +29 -0
- package/dist/chunk-CFLVPV5M.js.map +1 -0
- package/dist/chunk-EFGSH3MO.js +89 -0
- package/dist/chunk-EFGSH3MO.js.map +1 -0
- package/dist/chunk-FDBJNXH2.js +24 -0
- package/dist/chunk-FDBJNXH2.js.map +1 -0
- package/dist/chunk-M6MHLVSO.js +8 -0
- package/dist/chunk-M6MHLVSO.js.map +1 -0
- package/dist/chunk-U5GBGEGN.js +788 -0
- package/dist/chunk-U5GBGEGN.js.map +1 -0
- package/dist/chunk-VJTCFZNM.js +73 -0
- package/dist/chunk-VJTCFZNM.js.map +1 -0
- package/dist/chunk-WMRZSULD.js +567 -0
- package/dist/chunk-WMRZSULD.js.map +1 -0
- package/dist/chunk-Z27F4LBZ.js +6719 -0
- package/dist/chunk-Z27F4LBZ.js.map +1 -0
- package/dist/createTrueFoundryServer-B72bU-J7.d.ts +28 -0
- package/dist/index.d.ts +1573 -0
- package/dist/index.js +781 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/trueforge-agent-server-adapter/index.d.ts +475 -0
- package/dist/plugins/trueforge-agent-server-adapter/index.js +851 -0
- package/dist/plugins/trueforge-agent-server-adapter/index.js.map +1 -0
- package/dist/styles.css +2 -0
- package/package.json +129 -6
- package/index.js +0 -1
package/README.md
CHANGED
|
@@ -1,4 +1,641 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @truefoundry/trueforge-ui
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
[CI](https://github.com/truefoundry/trueforge/actions/workflows/ci.yml)
|
|
4
|
+
[npm](https://www.npmjs.com/package/@truefoundry/trueforge-ui)
|
|
5
|
+
[License](./LICENSE)
|
|
6
|
+
|
|
7
|
+
A themeable, composable React SDK for building production-ready AI agent chat applications.
|
|
8
|
+
Build your own agent chat platform with a flexible UI layer that works with **TrueFoundry** (Control Plane + Gateway), **TrueForge** (harness), or any custom backend. The SDK is fully open source, giving you complete control over your architecture, components, and integrations.
|
|
9
|
+
Powered by [assistant-ui](https://www.assistant-ui.com/), it follows the familiar **shadcn/ui** and **Tailwind CSS variable** theming conventions, making it easy to customize every aspect of the experience.
|
|
10
|
+
|
|
11
|
+
**Features**
|
|
12
|
+
|
|
13
|
+
- **Fully themeable** — Use built-in themes inspired by **TrueFoundry**, **ChatGPT**, **Claude**, and **Gemini**, or create your own brand identity.
|
|
14
|
+
- **Composable by design** — Swap layouts, components, and interaction patterns to fit your product.
|
|
15
|
+
- **Backend agnostic** — Connect to **TrueFoundry**, **TrueForge**, or any custom API via `TrueforgeServerConfig`.
|
|
16
|
+
- **Open source** — Extend, customize, and contribute without vendor lock-in.
|
|
17
|
+
- **Built on assistant-ui** — Leverage a modern React foundation with seamless shadcn/ui and Tailwind CSS integration.
|
|
18
|
+
- **Production ready** — Focus on your agents while the SDK handles the chat experience.
|
|
19
|
+
|
|
20
|
+
Bring your own **brand, colors, layout, components, and server**—the Agent SDK wires up the rest.
|
|
21
|
+
|
|
22
|
+
### Checkout the Demo [here](./example/)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Table of contents
|
|
27
|
+
|
|
28
|
+
- [Installation](#installation)
|
|
29
|
+
- [Getting started](#getting-started)
|
|
30
|
+
- [`<TrueforgeUI />` props](#trueforgeui--props)
|
|
31
|
+
- [Theming](#theming)
|
|
32
|
+
- [Content classNames](#content-classnames)
|
|
33
|
+
- [Brand / logo](#brand--logo)
|
|
34
|
+
- [Agent modes](#agent-modes)
|
|
35
|
+
- [Layouts](#layouts)
|
|
36
|
+
- [Custom layouts](#custom-layouts)
|
|
37
|
+
- [Overriding components](#overriding-components)
|
|
38
|
+
- [Server](#server)
|
|
39
|
+
- [Exports](#exports)
|
|
40
|
+
- [Docs](#docs)
|
|
41
|
+
- [License](#license)
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install @truefoundry/trueforge-ui
|
|
49
|
+
# or
|
|
50
|
+
pnpm add @truefoundry/trueforge-ui
|
|
51
|
+
# or
|
|
52
|
+
yarn add @truefoundry/trueforge-ui
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`react` / `react-dom` are required peers. The **host app must have
|
|
56
|
+
[Tailwind CSS](https://tailwindcss.com/) set up** (v4 recommended) so preflight
|
|
57
|
+
and your app chrome work alongside the SDK. In the host stylesheet:
|
|
58
|
+
|
|
59
|
+
```css
|
|
60
|
+
@import 'tailwindcss';
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
SDK styles (tokens, utilities, OpenUI) load automatically when `TrueforgeUI` /
|
|
64
|
+
`ThemeProvider` mounts — you do **not** need to import the SDK stylesheet for
|
|
65
|
+
client-only apps.
|
|
66
|
+
|
|
67
|
+
Optional (SSR / explicit load order):
|
|
68
|
+
|
|
69
|
+
```css
|
|
70
|
+
@import 'tailwindcss';
|
|
71
|
+
@import '@truefoundry/trueforge-ui/styles.css';
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
See [docs/compatibility.md](./docs/compatibility.md) for version ranges.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Getting started
|
|
79
|
+
|
|
80
|
+
**TrueFoundry** (`type: "truefoundry"`) — Control Plane + Gateway
|
|
81
|
+
|
|
82
|
+
Zero-config path: the SDK builds the agent UI server from your API key and
|
|
83
|
+
control plane URL (optional explicit gateway URL).
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { TrueforgeUI } from '@truefoundry/trueforge-ui';
|
|
87
|
+
|
|
88
|
+
export default function App() {
|
|
89
|
+
return (
|
|
90
|
+
<div style={{ height: '100dvh' }}>
|
|
91
|
+
<TrueforgeUI
|
|
92
|
+
server={{
|
|
93
|
+
type: 'truefoundry',
|
|
94
|
+
apiKey: process.env.TFY_API_KEY!,
|
|
95
|
+
controlPlaneURL: process.env.TFY_CONTROL_PLANE_URL!,
|
|
96
|
+
// gatewayPlaneURL: process.env.TFY_GATEWAY_URL, // optional
|
|
97
|
+
}}
|
|
98
|
+
layout="sidebar"
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**TrueForge** (`type: "trueforge"`) — Harness
|
|
106
|
+
|
|
107
|
+
Zero-config path for the TrueForge / Harness API. The SDK dynamically loads
|
|
108
|
+
`@truefoundry/trueforge-ui/plugins/trueforge-agent-server-adapter`, builds the
|
|
109
|
+
HTTP client, and composes chat + builder + default settings catalogs into an
|
|
110
|
+
`AgentUIServer`.
|
|
111
|
+
|
|
112
|
+
Install the SDK peer used by the adapter (workspace package in this monorepo):
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
pnpm add @truefoundry/trueforge-sdk
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Bearer token (embeds / remote API):**
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import { TrueforgeUI } from '@truefoundry/trueforge-ui';
|
|
122
|
+
|
|
123
|
+
export default function App() {
|
|
124
|
+
return (
|
|
125
|
+
<div style={{ height: '100dvh' }}>
|
|
126
|
+
<TrueforgeUI
|
|
127
|
+
server={{
|
|
128
|
+
type: 'trueforge',
|
|
129
|
+
baseUrl: process.env.TRUEFORGE_BASE_URL, // optional; default '/'
|
|
130
|
+
token: process.env.TRUEFORGE_TOKEN!,
|
|
131
|
+
}}
|
|
132
|
+
layout="sidebar"
|
|
133
|
+
/>
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Cookie / same-origin hosts** — omit `token` and inject `fetch` (e.g. an
|
|
140
|
+
auth-aware wrapper that follows OIDC cookies):
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
<TrueforgeUI
|
|
144
|
+
server={{
|
|
145
|
+
type: 'trueforge',
|
|
146
|
+
baseUrl: '/',
|
|
147
|
+
fetch: authAwareFetch,
|
|
148
|
+
}}
|
|
149
|
+
layout="sidebar"
|
|
150
|
+
agentConfig={{
|
|
151
|
+
mode: 'AgentLibraryWithComposer',
|
|
152
|
+
defaultAgentSpec: { model: { name: '…' } }, // often seeded at boot from listModels
|
|
153
|
+
}}
|
|
154
|
+
/>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Optional: pass `catalog` to override the built-in settings catalogs, or import
|
|
158
|
+
`createTrueForgeAgentUIServer` from
|
|
159
|
+
`@truefoundry/trueforge-ui/plugins/trueforge-agent-server-adapter` when you need
|
|
160
|
+
the factory outside `<TrueforgeUI />`.
|
|
161
|
+
|
|
162
|
+
**Custom** — bring your own `AgentUIServer`
|
|
163
|
+
|
|
164
|
+
Use this when you compose chat + builder yourself (e.g. chat-only gateway
|
|
165
|
+
adapter + stub catalog, or a full host BFF). Pass the server object directly.
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
import { TrueforgeUI, createTrueFoundryServer } from '@truefoundry/trueforge-ui';
|
|
169
|
+
import { createTrueFoundryChatServer } from '@truefoundry/assistant-ui-runtime/plugins/truefoundry-agent-server-adapter';
|
|
170
|
+
|
|
171
|
+
const chatServer = createTrueFoundryChatServer({
|
|
172
|
+
apiKey: process.env.TFY_API_KEY!,
|
|
173
|
+
baseUrl: process.env.TFY_GATEWAY_URL!,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const server = createTrueFoundryServer({
|
|
177
|
+
chatServer,
|
|
178
|
+
getModels: async () => [],
|
|
179
|
+
getSkills: async () => [],
|
|
180
|
+
getMcp: async () => [],
|
|
181
|
+
searchAgents: async () => [],
|
|
182
|
+
saveAgent: async () => ({}),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
export default function App() {
|
|
186
|
+
return (
|
|
187
|
+
<div style={{ height: '100dvh' }}>
|
|
188
|
+
<TrueforgeUI server={server} layout="sidebar" />
|
|
189
|
+
</div>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## `<TrueforgeUI />` props
|
|
195
|
+
|
|
196
|
+
`<TrueforgeUI />` is the single entry point. Every capability is driven by a prop.
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
<TrueforgeUI
|
|
200
|
+
server={{
|
|
201
|
+
type: 'truefoundry',
|
|
202
|
+
apiKey: process.env.TFY_API_KEY!,
|
|
203
|
+
controlPlaneURL: process.env.TFY_CONTROL_PLANE_URL!,
|
|
204
|
+
}} // or agentServer / { type: "trueforge", token?, baseUrl?, fetch? }
|
|
205
|
+
layout="sidebar" // 'sidebar' | 'drawer' | 'dock' | 'widget' | CustomLayout
|
|
206
|
+
agentConfig={{
|
|
207
|
+
mode: 'AgentLibraryWithComposer', // default when omitted
|
|
208
|
+
defaultAgentSpec: { model: { name: 'openai-main/gpt-4.1' } },
|
|
209
|
+
}}
|
|
210
|
+
theme={{
|
|
211
|
+
preset: 'claude',
|
|
212
|
+
brand: { name: 'Acme', logo: '/logo.svg' },
|
|
213
|
+
}}
|
|
214
|
+
overrides={{/* slot overrides */}}
|
|
215
|
+
className="h-full"
|
|
216
|
+
/>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
| Prop | Type | Required | Description |
|
|
220
|
+
| ------------------ | -------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
221
|
+
| `server` | `TrueforgeServerConfig` | ✅ | Built-in config (`truefoundry` / `trueforge`) **or** a ready `AgentUIServer`. |
|
|
222
|
+
| `layout` | `LayoutProp` | ✅ | Built-in layout string **or** a custom React component. |
|
|
223
|
+
| `agentConfig` | `AgentConfig` | — | Shell mode: SingleAgent / AgentLibrary / AgentComposer / AgentLibraryWithComposer. Defaults to library + composer. |
|
|
224
|
+
| `theme` | `ThemeConfig` | — | Preset, mode, tokens, brand, icons, **content `classNames`** (see [Theming](#theming)). |
|
|
225
|
+
| `overrides` | `SlotOverrides` | — | Map of slot overrides (see [Overriding components](#overriding-components)). |
|
|
226
|
+
| `className` | `string` | — | Applied to the layout root. |
|
|
227
|
+
| `initialSessionId` | `string` | — | Resume a specific session. |
|
|
228
|
+
| `onError` | `(error: unknown) => void` | — | Host error hook (runtime + server init). |
|
|
229
|
+
|
|
230
|
+
Later sections use `server` as a `TrueforgeServerConfig` (usually `type: "truefoundry"`). For a host-built port, pass the `AgentUIServer` directly.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Theming
|
|
235
|
+
|
|
236
|
+
Pass a preset and/or tokens and the whole UI adapts. Values map onto product CSS variables (`--primary-bg`, `--text-primary`, `--card-bg`, `--primary-button-bg`, `--failure-bg`, `--radius`, …), so no component needs palette-specific code.
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
const server = {
|
|
240
|
+
type: 'truefoundry' as const,
|
|
241
|
+
apiKey: process.env.TFY_API_KEY!,
|
|
242
|
+
controlPlaneURL: process.env.TFY_CONTROL_PLANE_URL!,
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
<TrueforgeUI
|
|
246
|
+
server={server}
|
|
247
|
+
layout="sidebar"
|
|
248
|
+
theme={{
|
|
249
|
+
preset: 'claude', // 'trueforge' | 'claude' | 'chatgpt' | 'gemini'
|
|
250
|
+
mode: 'dark', // omit for uncontrolled (useTheme().setTheme works)
|
|
251
|
+
tokens: {
|
|
252
|
+
primaryBg: 'oklch(0.14 0.02 260)',
|
|
253
|
+
textPrimary: 'oklch(0.97 0 0)',
|
|
254
|
+
secondaryBg: 'oklch(0.22 0.02 260)',
|
|
255
|
+
primaryButtonBg: 'oklch(0.55 0.2 275)',
|
|
256
|
+
primaryButtonHover: 'oklch(0.5 0.2 275)',
|
|
257
|
+
primaryButtonText: 'oklch(0.98 0 0)',
|
|
258
|
+
ghostButtonHover: 'oklch(0.8 0.12 200)',
|
|
259
|
+
radius: '0.5rem',
|
|
260
|
+
},
|
|
261
|
+
}}
|
|
262
|
+
/>;
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
You can also override tokens from host CSS on `.aui-theme-root` (inline `theme.tokens` still win over `:root`):
|
|
266
|
+
|
|
267
|
+
```css
|
|
268
|
+
.aui-theme-root {
|
|
269
|
+
--font-agent-ui: 'Your Font', ui-sans-serif, system-ui, sans-serif;
|
|
270
|
+
--primary-button-bg: oklch(0.55 0.2 275);
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
> _Screenshot: the same layout rebranded with a custom palette._
|
|
275
|
+
|
|
276
|
+
See [docs/theming.md](./docs/theming.md) for presets, controlled vs uncontrolled mode, and deeper theming notes.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Content classNames
|
|
281
|
+
|
|
282
|
+
Style content renderers (markdown, code fences, OpenUI, Monaco) without swapping
|
|
283
|
+
slots. Pass `theme.classNames` on `<TrueforgeUI />` — values merge onto the
|
|
284
|
+
defaults via `cn()`:
|
|
285
|
+
|
|
286
|
+
```tsx
|
|
287
|
+
<TrueforgeUI
|
|
288
|
+
server={server}
|
|
289
|
+
layout="sidebar"
|
|
290
|
+
theme={{
|
|
291
|
+
classNames: {
|
|
292
|
+
markdown: 'prose prose-neutral dark:prose-invert max-w-none',
|
|
293
|
+
inlineCode: 'font-semibold',
|
|
294
|
+
syntaxHighlighter: {
|
|
295
|
+
root: 'my-code-block rounded-lg',
|
|
296
|
+
pre: 'bg-zinc-950 p-4',
|
|
297
|
+
code: 'text-sm font-mono',
|
|
298
|
+
lineNumber: 'opacity-60',
|
|
299
|
+
},
|
|
300
|
+
openui: { root: 'my-openui-host', scope: 'p-2' },
|
|
301
|
+
monaco: { root: 'my-monaco h-64', editor: 'rounded-lg', monacoTheme: 'vs-dark' },
|
|
302
|
+
},
|
|
303
|
+
}}
|
|
304
|
+
/>
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
| `theme.classNames` key | Component / surface | Fields |
|
|
308
|
+
| ---------------------- | ------------------------------------------- | ------------------------------------------------- |
|
|
309
|
+
| `markdown` | `Markdown` (message prose root) | `string` |
|
|
310
|
+
| `inlineCode` | `Markdown` inline `` `code` `` | `string` |
|
|
311
|
+
| `syntaxHighlighter` | `SyntaxHighlighter` (non-OpenUI fences) | `root`, `pre`, `code`, `lineNumber` |
|
|
312
|
+
| `openui` | `OpenUiFenceBlock` | `root`, `scope` |
|
|
313
|
+
| `monaco` | `MonacoEditorCore` (code artifacts / diffs) | `root`, `editor`, `monacoTheme` (Monaco theme id) |
|
|
314
|
+
|
|
315
|
+
Custom layouts and host atoms under the provider can read the same map with
|
|
316
|
+
`useOptionalContentClassNames()` / `useContentClassNames()` (exported from the
|
|
317
|
+
package). Host CSS on `.aui-markdown` / `.aui-syntax-highlighter` / `.aui-openui`
|
|
318
|
+
/ `.aui-monaco` still works as an alternative.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Brand / logo
|
|
323
|
+
|
|
324
|
+
**Base layouts** — pass `theme.brand` and the SDK positions the mark + name in the default slots:
|
|
325
|
+
|
|
326
|
+
```tsx
|
|
327
|
+
<TrueforgeUI
|
|
328
|
+
server={server}
|
|
329
|
+
layout="sidebar"
|
|
330
|
+
theme={{
|
|
331
|
+
brand: {
|
|
332
|
+
name: 'Acme',
|
|
333
|
+
logo: '/brand/logo.svg',
|
|
334
|
+
},
|
|
335
|
+
}}
|
|
336
|
+
/>
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Light / dark marks** — pass `light` / `dark` sources instead and the SDK picks the one matching
|
|
340
|
+
the resolved mode. `href` wraps the logo in a same-tab link:
|
|
341
|
+
|
|
342
|
+
```tsx
|
|
343
|
+
<TrueforgeUI
|
|
344
|
+
server={server}
|
|
345
|
+
layout="sidebar"
|
|
346
|
+
theme={{
|
|
347
|
+
brand: {
|
|
348
|
+
name: 'Acme',
|
|
349
|
+
logo: { light: '/brand/logo-light.svg', dark: '/brand/logo-dark.svg', href: '/' },
|
|
350
|
+
},
|
|
351
|
+
}}
|
|
352
|
+
/>
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Set only one mode and it is used for both. `name` labels the image, so no `alt` is needed.
|
|
356
|
+
|
|
357
|
+
**Component marks** — `theme.brand` takes image URLs only. To render an inline SVG or a custom
|
|
358
|
+
component, override the `BrandLogo` slot, the same way you replace any other atom:
|
|
359
|
+
|
|
360
|
+
```tsx
|
|
361
|
+
<TrueforgeUI server={server} layout="sidebar" overrides={{ BrandLogo: MyMark }} />
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Custom layouts** — import `BrandLogo` and place it anywhere; pair it with `useBrandName()` when you also want the name as text (see [Custom layouts](#custom-layouts)).
|
|
365
|
+
|
|
366
|
+
> _Screenshot: external brand mark rendered in the base layout header._
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## Agent modes
|
|
371
|
+
|
|
372
|
+
`agentConfig` controls library chrome, draft composer, and how New Chat / Clear Chat behave.
|
|
373
|
+
|
|
374
|
+
| Mode | Layout chrome | Agent selection / New Chat |
|
|
375
|
+
| -------------------------------------- | ------------------------------- | --------------------------------------------------------- |
|
|
376
|
+
| `AgentLibraryWithComposer` _(default)_ | Agents Library + draft builder | New Chat opens draft; library picks a named agent |
|
|
377
|
+
| `SingleAgent` | Named-only, plain composer | Locked to `name`; New Chat / Clear Chat = new thread |
|
|
378
|
+
| `AgentLibrary` | Agents Library only (no draft) | Empty until pick; no New Chat; Clear Chat after selection |
|
|
379
|
+
| `AgentComposer` | Draft builder only (no library) | Always draft; New Chat / Clear Chat = fresh draft |
|
|
380
|
+
|
|
381
|
+
In library modes, picking an agent from the Agents Library 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.
|
|
382
|
+
|
|
383
|
+
```tsx
|
|
384
|
+
{
|
|
385
|
+
/* Library + draft (default) */
|
|
386
|
+
}
|
|
387
|
+
<TrueforgeUI server={server} layout="sidebar" />;
|
|
388
|
+
|
|
389
|
+
{
|
|
390
|
+
/* Named-only lock */
|
|
391
|
+
}
|
|
392
|
+
<TrueforgeUI server={server} layout="sidebar" agentConfig={{ mode: 'SingleAgent', name: 'support-agent' }} />;
|
|
393
|
+
|
|
394
|
+
{
|
|
395
|
+
/* Library only — select an agent to start */
|
|
396
|
+
}
|
|
397
|
+
<TrueforgeUI server={server} layout="sidebar" agentConfig={{ mode: 'AgentLibrary' }} />;
|
|
398
|
+
|
|
399
|
+
{
|
|
400
|
+
/* Composer only */
|
|
401
|
+
}
|
|
402
|
+
<TrueforgeUI
|
|
403
|
+
server={server}
|
|
404
|
+
layout="sidebar"
|
|
405
|
+
agentConfig={{
|
|
406
|
+
mode: 'AgentComposer',
|
|
407
|
+
defaultAgentSpec: { model: { name: 'openai-main/gpt-4.1' } },
|
|
408
|
+
}}
|
|
409
|
+
/>;
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
> _Screenshot: Agents Library open; selecting an agent resets the thread._
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## Layouts
|
|
417
|
+
|
|
418
|
+
Built-in `layout` values:
|
|
419
|
+
|
|
420
|
+
| Value | Description |
|
|
421
|
+
| --------- | -------------------------------------------------------- |
|
|
422
|
+
| `sidebar` | Left session list + main thread (ChatGPT / Claude style) |
|
|
423
|
+
| `drawer` | Full-bleed thread; sessions open in a slide-over |
|
|
424
|
+
| `dock` | Fixed-width right panel; list XOR thread stack |
|
|
425
|
+
| `widget` | Same stack as `dock`, opened from a bottom-right FAB |
|
|
426
|
+
|
|
427
|
+
The [example app](./example/) switches between these four modes.
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Custom layouts
|
|
432
|
+
|
|
433
|
+
For full control, pass a React component as `layout`. The SDK still wires server, shell mode, slots, and runtime behind it.
|
|
434
|
+
|
|
435
|
+
```tsx
|
|
436
|
+
import { Thread, ThreadListContainer, BrandLogo, useBrandName, useTheme } from '@truefoundry/trueforge-ui';
|
|
437
|
+
|
|
438
|
+
function Layout({ className }: { className?: string }) {
|
|
439
|
+
const { mode, setTheme } = useTheme();
|
|
440
|
+
const brandName = useBrandName();
|
|
441
|
+
|
|
442
|
+
return (
|
|
443
|
+
<div className={className} style={{ display: 'flex', height: '100%' }}>
|
|
444
|
+
<aside style={{ width: 256 }}>
|
|
445
|
+
<BrandLogo className="size-6" />
|
|
446
|
+
<span>{brandName}</span>
|
|
447
|
+
<ThreadListContainer />
|
|
448
|
+
</aside>
|
|
449
|
+
<main style={{ flex: 1, minWidth: 0 }}>
|
|
450
|
+
<button type="button" onClick={() => setTheme(mode === 'dark' ? 'light' : 'dark')}>
|
|
451
|
+
Theme
|
|
452
|
+
</button>
|
|
453
|
+
<Thread />
|
|
454
|
+
</main>
|
|
455
|
+
</div>
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
<TrueforgeUI server={server} layout={Layout} />;
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
For deeper composition without `TrueforgeUI`, nest `SlotsProvider` outside `TrueFoundryChatProvider` — see [docs/customization.md](./docs/customization.md).
|
|
463
|
+
|
|
464
|
+
> _Screenshot: a custom layout assembled from_ `BrandLogo`_,_ `ThreadListContainer`_, and_ `Thread`_._
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
## Overriding components
|
|
469
|
+
|
|
470
|
+
Every curated feature atom is overridable. Provide an `overrides` map to swap any single component while inheriting the rest.
|
|
471
|
+
|
|
472
|
+
```tsx
|
|
473
|
+
import { TrueforgeUI, type AssistantMessageBubbleProps } from '@truefoundry/trueforge-ui';
|
|
474
|
+
|
|
475
|
+
function MyBubble({ children, error, actionBar, className }: AssistantMessageBubbleProps) {
|
|
476
|
+
return (
|
|
477
|
+
<div className={`flex flex-col gap-2 border-l-2 border-primary-button-bg pl-3.5 ${className ?? ''}`}>
|
|
478
|
+
{error ? <div className="rounded-lg bg-failure-bg/10 px-2.5 py-2 text-sm text-failure-bg">{error}</div> : null}
|
|
479
|
+
<div>{children}</div>
|
|
480
|
+
{actionBar}
|
|
481
|
+
</div>
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
<TrueforgeUI
|
|
486
|
+
server={server}
|
|
487
|
+
layout="sidebar"
|
|
488
|
+
overrides={{
|
|
489
|
+
AssistantMessageBubble: MyBubble,
|
|
490
|
+
// WelcomeScreen, ComposerShell, ToolCallCard, … all overridable
|
|
491
|
+
}}
|
|
492
|
+
/>;
|
|
493
|
+
```
|
|
494
|
+
|
|
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).
|
|
496
|
+
|
|
497
|
+
See [docs/customization.md](./docs/customization.md) for the full slot list.
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## Server
|
|
502
|
+
|
|
503
|
+
`<TrueforgeUI />` takes a **`TrueforgeServerConfig`**: built-in backends init
|
|
504
|
+
inside the component, or pass a ready `AgentUIServer` directly.
|
|
505
|
+
|
|
506
|
+
```ts
|
|
507
|
+
type TrueforgeServerConfig =
|
|
508
|
+
| {
|
|
509
|
+
type: 'truefoundry';
|
|
510
|
+
apiKey: string;
|
|
511
|
+
controlPlaneURL: string;
|
|
512
|
+
gatewayPlaneURL?: string;
|
|
513
|
+
}
|
|
514
|
+
| {
|
|
515
|
+
type: 'trueforge';
|
|
516
|
+
baseUrl?: string;
|
|
517
|
+
token?: string;
|
|
518
|
+
fetch?: typeof fetch;
|
|
519
|
+
catalog?: CatalogServer;
|
|
520
|
+
}
|
|
521
|
+
| AgentUIServer;
|
|
522
|
+
|
|
523
|
+
type AgentUIServer = AgentChatServer & AgentBuilderServer & { catalog?: CatalogServer };
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
| Port | Responsibility |
|
|
527
|
+
| -------------------- | ------------------------------------------------------------------- |
|
|
528
|
+
| `AgentChatServer` | Sessions, turns, streaming, draft `AgentSpec` sync |
|
|
529
|
+
| `AgentBuilderServer` | `getModels` / `getSkills` / `getMcp` / `searchAgents` / `saveAgent` |
|
|
530
|
+
|
|
531
|
+
**Zero-config TrueFoundry** — see [Getting started](#getting-started). The SDK calls `createTrueFoundryAgentUIServer` for you.
|
|
532
|
+
|
|
533
|
+
**Zero-config TrueForge (Harness)** — see [Getting started](#getting-started).
|
|
534
|
+
`type: "trueforge"` resolves via
|
|
535
|
+
`@truefoundry/trueforge-ui/plugins/trueforge-agent-server-adapter`
|
|
536
|
+
(`createTrueForgeAgentUIServer`: chat + builder + default catalogs). Auth is
|
|
537
|
+
host-owned: pass `token` and/or `fetch`.
|
|
538
|
+
|
|
539
|
+
**Compose your own `AgentUIServer` (custom):**
|
|
540
|
+
|
|
541
|
+
```tsx
|
|
542
|
+
import { TrueforgeUI, createTrueFoundryServer } from '@truefoundry/trueforge-ui';
|
|
543
|
+
import { createTrueFoundryChatServer } from '@truefoundry/assistant-ui-runtime/plugins/truefoundry-agent-server-adapter';
|
|
544
|
+
|
|
545
|
+
const chatServer = createTrueFoundryChatServer({ apiKey, baseUrl });
|
|
546
|
+
const agentServer = createTrueFoundryServer({
|
|
547
|
+
chatServer,
|
|
548
|
+
getModels,
|
|
549
|
+
getSkills,
|
|
550
|
+
getMcp,
|
|
551
|
+
searchAgents,
|
|
552
|
+
saveAgent,
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
<TrueforgeUI server={agentServer} layout="sidebar" />;
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
**Implement `AgentUIServer` yourself:**
|
|
559
|
+
|
|
560
|
+
```tsx
|
|
561
|
+
import { TrueforgeUI, type AgentUIServer } from '@truefoundry/trueforge-ui';
|
|
562
|
+
|
|
563
|
+
const agentServer: AgentUIServer = {
|
|
564
|
+
// AgentChatServer methods…
|
|
565
|
+
createSession,
|
|
566
|
+
listSessions,
|
|
567
|
+
getSession,
|
|
568
|
+
updateSession,
|
|
569
|
+
createTurn,
|
|
570
|
+
// …
|
|
571
|
+
// AgentBuilderServer methods…
|
|
572
|
+
getModels: async () => [],
|
|
573
|
+
getSkills: async () => [],
|
|
574
|
+
getMcp: async () => [],
|
|
575
|
+
searchAgents: async () => [],
|
|
576
|
+
saveAgent: async ({ agentName, agentSpec }) => ({ ok: true }),
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
<TrueforgeUI server={agentServer} layout="sidebar" />;
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
See [docs/server.md](./docs/server.md) for the full method list and BYO guidance.
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## Exports
|
|
587
|
+
|
|
588
|
+
| Export | Kind | Purpose |
|
|
589
|
+
| ------------------------------------------------------------------ | ---------- | ------------------------------------------------------------ |
|
|
590
|
+
| `TrueforgeUI` | Component | Root component — accepts all props above |
|
|
591
|
+
| `TrueforgeServerConfig` | Type | `server` prop: `truefoundry` / `trueforge` / `AgentUIServer` |
|
|
592
|
+
| `createTrueFoundryServer` | Function | Compose chat + builder into `AgentUIServer` |
|
|
593
|
+
| `Thread`, `ThreadListContainer`, `BrandLogo` | Components | Layout primitives for custom layouts |
|
|
594
|
+
| Composer / message / tool atoms | Components | Overridable, themeable building blocks |
|
|
595
|
+
| `SlotsProvider`, `useSlot`, `useTheme` | API | Overrides + theme mode |
|
|
596
|
+
| `AgentUIServer`, `AgentChatServer`, `AgentBuilderServer` | Types | Resolved server contract |
|
|
597
|
+
| `ThemeConfig`, `LayoutProp`, `SlotOverrides`, `AgentSpec`, … | Types | Configuration contracts |
|
|
598
|
+
| `@truefoundry/trueforge-ui/styles.css` | CSS | Optional; auto-injected by `ThemeProvider` |
|
|
599
|
+
| `@truefoundry/trueforge-ui/assistant-ui` | Entry | Shared `useAui` / `useAuiState` (single instance) |
|
|
600
|
+
| `@truefoundry/trueforge-ui/plugins/trueforge-agent-server-adapter` | Entry | `createTrueForgeAgentUIServer` + Harness catalogs / chat |
|
|
601
|
+
|
|
602
|
+
Curated public API: [docs/api.md](./docs/api.md).
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
## Docs
|
|
607
|
+
|
|
608
|
+
| Doc | Topic |
|
|
609
|
+
| ------------------------------------------------ | ----------------------------- |
|
|
610
|
+
| [docs/api.md](./docs/api.md) | Curated public API |
|
|
611
|
+
| [docs/architecture.md](./docs/architecture.md) | Atoms, containers, slots |
|
|
612
|
+
| [docs/customization.md](./docs/customization.md) | Theme, slots, custom layout |
|
|
613
|
+
| [docs/compatibility.md](./docs/compatibility.md) | Peer matrix |
|
|
614
|
+
| [docs/server.md](./docs/server.md) | Server port + BYO |
|
|
615
|
+
| [docs/theming.md](./docs/theming.md) | Themes, brand, icons, presets |
|
|
616
|
+
| [CHANGELOG.md](./CHANGELOG.md) | Migration notes |
|
|
617
|
+
|
|
618
|
+
### Troubleshooting: "requires an AuiProvider"
|
|
619
|
+
|
|
620
|
+
Usually duplicate `@assistant-ui/core` / `@assistant-ui/store` instances. Diagnose with `pnpm why`, align `react` across the workspace, and import chrome hooks from `@truefoundry/trueforge-ui` (or `/assistant-ui`) so you share the SDK’s copy.
|
|
621
|
+
|
|
622
|
+
### Development
|
|
623
|
+
|
|
624
|
+
From the monorepo root:
|
|
625
|
+
|
|
626
|
+
```bash
|
|
627
|
+
pnpm install
|
|
628
|
+
pnpm --filter @truefoundry/trueforge-ui typecheck
|
|
629
|
+
pnpm --filter @truefoundry/trueforge-ui test
|
|
630
|
+
pnpm --filter @truefoundry/trueforge-ui build
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
Local demo: see [example/](./example/). Publishing: see [RELEASING.md](../../RELEASING.md#releasing-truefoundrytrueforge-ui).
|
|
634
|
+
|
|
635
|
+
---
|
|
636
|
+
|
|
637
|
+
## License
|
|
638
|
+
|
|
639
|
+
MIT. See [LICENSE](./LICENSE) and [NOTICE](./NOTICE).
|
|
640
|
+
|
|
641
|
+
Security: [SECURITY.md](./SECURITY.md) · Conduct: [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) · Changes: [CHANGELOG.md](./CHANGELOG.md)
|