@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.
Files changed (55) hide show
  1. package/CHANGELOG.md +348 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE +17 -0
  4. package/README.md +640 -3
  5. package/dist/ConnectorSettings-ADACLWQI.js +898 -0
  6. package/dist/ConnectorSettings-ADACLWQI.js.map +1 -0
  7. package/dist/DockLayout-BH5XX2AQ.js +35 -0
  8. package/dist/DockLayout-BH5XX2AQ.js.map +1 -0
  9. package/dist/DrawerLayout-O2XZQCG4.js +156 -0
  10. package/dist/DrawerLayout-O2XZQCG4.js.map +1 -0
  11. package/dist/ModelSettings-LKFJVUYQ.js +1082 -0
  12. package/dist/ModelSettings-LKFJVUYQ.js.map +1 -0
  13. package/dist/OpenUiFenceBlock-A2CWCPOP.js +9 -0
  14. package/dist/OpenUiFenceBlock-A2CWCPOP.js.map +1 -0
  15. package/dist/SandboxSettings-H5MDAE47.js +505 -0
  16. package/dist/SandboxSettings-H5MDAE47.js.map +1 -0
  17. package/dist/SettingsBuilder-3JOLC56Z.js +136 -0
  18. package/dist/SettingsBuilder-3JOLC56Z.js.map +1 -0
  19. package/dist/SidebarLayout-G6BGD7EY.js +236 -0
  20. package/dist/SidebarLayout-G6BGD7EY.js.map +1 -0
  21. package/dist/SkillSettings-4VB42CVG.js +389 -0
  22. package/dist/SkillSettings-4VB42CVG.js.map +1 -0
  23. package/dist/WidgetLayout-ABSXZUSQ.js +101 -0
  24. package/dist/WidgetLayout-ABSXZUSQ.js.map +1 -0
  25. package/dist/assistant-ui.d.ts +1 -0
  26. package/dist/assistant-ui.js +9 -0
  27. package/dist/assistant-ui.js.map +1 -0
  28. package/dist/chunk-3PTFNAQK.js +2088 -0
  29. package/dist/chunk-3PTFNAQK.js.map +1 -0
  30. package/dist/chunk-CFLVPV5M.js +29 -0
  31. package/dist/chunk-CFLVPV5M.js.map +1 -0
  32. package/dist/chunk-EFGSH3MO.js +89 -0
  33. package/dist/chunk-EFGSH3MO.js.map +1 -0
  34. package/dist/chunk-FDBJNXH2.js +24 -0
  35. package/dist/chunk-FDBJNXH2.js.map +1 -0
  36. package/dist/chunk-M6MHLVSO.js +8 -0
  37. package/dist/chunk-M6MHLVSO.js.map +1 -0
  38. package/dist/chunk-U5GBGEGN.js +788 -0
  39. package/dist/chunk-U5GBGEGN.js.map +1 -0
  40. package/dist/chunk-VJTCFZNM.js +73 -0
  41. package/dist/chunk-VJTCFZNM.js.map +1 -0
  42. package/dist/chunk-WMRZSULD.js +567 -0
  43. package/dist/chunk-WMRZSULD.js.map +1 -0
  44. package/dist/chunk-Z27F4LBZ.js +6719 -0
  45. package/dist/chunk-Z27F4LBZ.js.map +1 -0
  46. package/dist/createTrueFoundryServer-B72bU-J7.d.ts +28 -0
  47. package/dist/index.d.ts +1573 -0
  48. package/dist/index.js +781 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/plugins/trueforge-agent-server-adapter/index.d.ts +475 -0
  51. package/dist/plugins/trueforge-agent-server-adapter/index.js +851 -0
  52. package/dist/plugins/trueforge-agent-server-adapter/index.js.map +1 -0
  53. package/dist/styles.css +2 -0
  54. package/package.json +129 -6
  55. package/index.js +0 -1
package/README.md CHANGED
@@ -1,4 +1,641 @@
1
- # `@truefoundry/trueforge-ui`
1
+ # @truefoundry/trueforge-ui
2
2
 
3
- Placeholder `0.0.0` so npm trusted publishing can be attached to this package.
4
- Not a functional release. Install a later version.
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)