Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,20 @@
{
"group": "Server Customisations",
"pages": [
"ui-sdk/setup-custom-servers/overview",
"ui-sdk/setup-custom-servers/connect-with-trueforge",
"ui-sdk/setup-custom-servers/connect-with-truefoundry",
"ui-sdk/setup-custom-servers/custom-server",
{
"group": "Bring your own server",
"pages": [
"ui-sdk/setup-custom-servers/custom-server",
"ui-sdk/setup-custom-servers/core-concepts",
"ui-sdk/setup-custom-servers/chat",
"ui-sdk/setup-custom-servers/catalog",
"ui-sdk/setup-custom-servers/agents",
"ui-sdk/setup-custom-servers/putting-it-together"
]
},
"ui-sdk/setup-custom-servers/server-contract"
]
},
Expand Down
4 changes: 2 additions & 2 deletions docs/ui-sdk/concepts/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Two kinds of component are exported, and the distinction determines which one yo

**Atoms** are presentational. `AssistantMessageBubble`, `ComposerShell`, and `ToolCallCard` take everything they render as props and hold no runtime state. You rarely render an atom directly — instead you replace one, and the container that renders it picks up your version.

That replacement is what `overrides` does: name a component, supply your own, and it is used everywhere that component appears. See [Slot overrides](/ui-sdk/guides/slot-overrides).
That replacement is what `overrides` does: name a component, supply your own, and it is used everywhere that component appears. See [Slot overrides](/ui-sdk/setup-custom-ui/slot-overrides).

## Provider stack

Expand Down Expand Up @@ -53,4 +53,4 @@ Order matters: `SlotsProvider` must be outside `TrueFoundryChatProvider`.

These class names and attributes are stable and safe to target from your own CSS: `.aui-root`, `.aui-theme-root`, `.aui-markdown`, `.aui-syntax-highlighter`, `.aui-openui`, `.aui-monaco`, plus `data-slot` attributes on individual components. Most slot values are prefixed `aui_`, but not all — `avatar`, `tool-call-card`, and `tool-group-card` are among the unprefixed ones, so inspect the element rather than assuming the prefix.

For token-level changes, prefer [theming](/ui-sdk/guides/theming) over CSS overrides.
For token-level changes, prefer [theming](/ui-sdk/setup-custom-ui/custom-theme) over CSS overrides.
2 changes: 2 additions & 0 deletions docs/ui-sdk/get-started/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export default function App() {

That is enough to get a full agent chat with streaming, history, and tool calls.

For TrueFoundry, a custom `AgentUIServer`, auth, or catalog overrides, see [Server Customisations](/ui-sdk/setup-custom-servers/overview).

<Frame caption="What `TrueforgeUI` renders — a full agent chat with streaming, history, and tool calls.">
![The TrueforgeUI component rendering an agent chat with an agent-steps panel and a streamed response](/images/agent-composer-with-library.png)
</Frame>
4 changes: 2 additions & 2 deletions docs/ui-sdk/guides/troubleshooting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ description: "Common failure modes and their causes."
</Accordion>

<Accordion title="Only the OAuth screen renders — no chat">
A `screenType=mcp-auth` query parameter is present on the URL. `TrueforgeUI` renders the OAuth completion screen exclusively in that case. Keep the callback on its own route; see [MCP OAuth](/ui-sdk/guides/mcp-oauth).
A `screenType=mcp-auth` query parameter is present on the URL. `TrueforgeUI` renders the OAuth completion screen exclusively in that case. Keep the callback on its own route; see [MCP OAuth](/ui-sdk/setup-custom-ui/mcp-oauth).
</Accordion>

<Accordion title="Dark mode fights with the host application">
The provider toggles the `dark` class on `document.documentElement`. Pass a controlled `theme.mode` derived from your own state so the two stay aligned.
</Accordion>

<Accordion title="Import of Button or AskUserPrompt fails">
A few names are published as types only, so importing them as values fails. `Button` and `IconButton` are restyled through [theme tokens](/ui-sdk/guides/theming) rather than replaced. `AskUserPrompt`, `McpAuthPrompt`, and `ReasoningCard` are override-only — supply your own component typed with the published props.
A few names are published as types only, so importing them as values fails. `Button` and `IconButton` are restyled through [theme tokens](/ui-sdk/setup-custom-ui/custom-theme) rather than replaced. `AskUserPrompt`, `McpAuthPrompt`, and `ReasoningCard` are override-only — supply your own component typed with the published props.
</Accordion>

<Accordion title="SSR or React Server Components errors">
Expand Down
6 changes: 3 additions & 3 deletions docs/ui-sdk/reference/atoms.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: "Presentational components and their prop types."

Atoms are pure presentational components. Most publish a matching `*Props` type, and most are
overridable slots — but neither is universal, so check
[Slot overrides](/ui-sdk/guides/slot-overrides) for which names `overrides` accepts, and rely on your
[Slot overrides](/ui-sdk/setup-custom-ui/slot-overrides) for which names `overrides` accepts, and rely on your
editor for which props types exist.

## Messages and content
Expand Down Expand Up @@ -79,7 +79,7 @@ type ToolCallCardProps = {
<Warning>
`icon` is an icon **name** looked up in the icon registry, not a rendered node — it defaults
to `"mcp-server"`. Passing an element renders nothing useful. To supply your own artwork, map
the name through `theme.icons`; see [Theming](/ui-sdk/guides/theming).
the name through `theme.icons`; see [Theming](/ui-sdk/setup-custom-ui/custom-theme).
</Warning>

Also `ToolCallContentBlock`, `ToolApprovalBar`, `ToolGroupCard`, `SubAgentCard`,
Expand Down Expand Up @@ -115,5 +115,5 @@ theme and settings buttons.
<Note>
`ButtonProps`, `ButtonVariant`, `ButtonSize`, and `IconButtonProps` are available as types
for typing your own components. The buttons themselves are styled through semantic tokens
rather than replaced — see [Theming](/ui-sdk/guides/theming).
rather than replaced — see [Theming](/ui-sdk/setup-custom-ui/custom-theme).
</Note>
4 changes: 2 additions & 2 deletions docs/ui-sdk/reference/catalog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "Settings catalog"
description: "The optional catalog port behind the model, connector, skill, and sandbox settings."
---

`catalog` is the optional fourth part of an [`AgentUIServer`](/ui-sdk/concepts/server-contract). Attach
`catalog` is the optional fourth part of an [`AgentUIServer`](/ui-sdk/setup-custom-servers/server-contract). Attach
it and the settings UI appears; omit it and those surfaces stay hidden.

```ts
Expand Down Expand Up @@ -234,7 +234,7 @@ must render either way.
## Widening

Every catalog interface is generic over its row and request types, following the same pattern as
[the chat and builder ports](/ui-sdk/concepts/server-contract#widening-the-types):
[the chat and builder ports](/ui-sdk/setup-custom-servers/server-contract#widening-the-types):

```ts
interface MyModelEntry extends ModelEntry {
Expand Down
8 changes: 4 additions & 4 deletions docs/ui-sdk/reference/events.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ interface TurnStreamData {
</Note>

`sequenceNumber` must increase monotonically within a turn. It is what
[`subscribeToTurn`](/ui-sdk/concepts/server-contract#agentchatserver) uses to resume — a reconnecting
[`subscribeToTurn`](/ui-sdk/setup-custom-servers/server-contract#agentchatserver) uses to resume — a reconnecting
client passes the last number it saw as `afterSequenceNumber`, and you replay only what follows.

```ts
Expand Down Expand Up @@ -222,7 +222,7 @@ interface McpAuthRequiredEvent {
}
```

`authUrl` is the URL the popup opens. See [MCP OAuth](/ui-sdk/guides/mcp-oauth).
`authUrl` is the URL the popup opens. See [MCP OAuth](/ui-sdk/setup-custom-ui/mcp-oauth).

<Note>
These events also appear in `requiredActions` on a `done` turn state. That is how a turn that
Expand All @@ -231,7 +231,7 @@ interface McpAuthRequiredEvent {
</Note>

The user's reply comes back through `createTurn` as a `user.tool_approval` or
`user.tool_response` [input item](/ui-sdk/concepts/server-contract#turn-input), carrying the same
`user.tool_response` [input item](/ui-sdk/setup-custom-servers/server-contract#turn-input), carrying the same
`toolCallId`.

## Sub-agents
Expand Down Expand Up @@ -277,7 +277,7 @@ interface SandboxCreatedEvent {
```

`sandboxId` is what you pass to
[`downloadSandboxFile`](/ui-sdk/concepts/server-contract#agentchatserver) to retrieve artifacts the
[`downloadSandboxFile`](/ui-sdk/setup-custom-servers/server-contract#agentchatserver) to retrieve artifacts the
agent produced.

`mcp.initialize` (`{ type, id, createdAt, threadId }`, plus any additional fields you attach)
Expand Down
4 changes: 2 additions & 2 deletions docs/ui-sdk/reference/hooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const capabilities = useServerCapabilities();
Returns the resolved value from your server's `getCapabilities()`, or `null` while it is still
loading or if the call failed. Use it to gate your own chrome the same way the SDK gates its
sandbox, skill, and settings affordances. See
[Server contract](/ui-sdk/concepts/server-contract#capabilities).
[Server contract](/ui-sdk/setup-custom-servers/server-contract#capabilities).

## MCP auth

Expand All @@ -34,7 +34,7 @@ const auth = useMCPAuth({ callbackPath: "/mcp-callback" });

`MCP_AUTH_POPUP_CHANNEL` is `"truefoundry-mcp-auth-popup"` — the `BroadcastChannel` name used
to signal completion back to the opener. Types: `McpAuthCallback`, `McpAuthPopupMessage`,
`UseMCPAuthOptions`. See [MCP OAuth](/ui-sdk/guides/mcp-oauth).
`UseMCPAuthOptions`. See [MCP OAuth](/ui-sdk/setup-custom-ui/mcp-oauth).

## assistant-ui state

Expand Down
4 changes: 2 additions & 2 deletions docs/ui-sdk/reference/server.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,5 @@ to reference:
</Accordion>
</AccordionGroup>

Full method signatures are on [Server contract](/ui-sdk/concepts/server-contract); a worked
implementation is on [Bring your own server](/ui-sdk/guides/custom-server).
Full method signatures are on [Server contract](/ui-sdk/setup-custom-servers/server-contract); a worked
implementation is on [Bring your own server](/ui-sdk/setup-custom-servers/custom-server).
4 changes: 2 additions & 2 deletions docs/ui-sdk/reference/theme.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ type SlotOverrides = Partial<AtomSlots>;

`AtomSlots` is derived from the SDK's default slot table, so it enumerates exactly the
overridable slots — your editor's autocomplete on `overrides` is authoritative. See
[Slot overrides](/ui-sdk/guides/slot-overrides).
[Slot overrides](/ui-sdk/setup-custom-ui/slot-overrides).

Most token names map to a CSS variable of the same name; the exceptions are listed in
[Theming](/ui-sdk/guides/theming).
[Theming](/ui-sdk/setup-custom-ui/custom-theme).
6 changes: 3 additions & 3 deletions docs/ui-sdk/reference/trueforge-ui.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,13 @@ import { TrueforgeUI } from "@truefoundry/trueforge-ui";
</ParamField>
</Expandable>

See [Theming](/ui-sdk/guides/theming).
See [Theming](/ui-sdk/setup-custom-ui/custom-theme).
</ParamField>

<ParamField path="overrides" type="SlotOverrides">
Replace any built-in component. `Partial<AtomSlots>`, derived from the SDK's default slot
table — so editor autocomplete lists the overridable names. See
[Slot overrides](/ui-sdk/guides/slot-overrides).
[Slot overrides](/ui-sdk/setup-custom-ui/slot-overrides).
</ParamField>

<ParamField path="className" type="string">
Expand Down Expand Up @@ -228,7 +228,7 @@ Persisted sessions remain available through the thread list.

<Warning>
If `window.location.search` contains `screenType=mcp-auth`, the component renders only the
OAuth completion screen and no layout. See [MCP OAuth](/ui-sdk/guides/mcp-oauth).
OAuth completion screen and no layout. See [MCP OAuth](/ui-sdk/setup-custom-ui/mcp-oauth).
</Warning>

## Example
Expand Down
81 changes: 81 additions & 0 deletions docs/ui-sdk/setup-custom-servers/agents.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
title: "Agents"
description: "Implement AgentBuilderServer — capabilities, pickers, and the agent library."
---

`AgentBuilderServer` powers the agent library and the draft composer. It is required on every `AgentUIServer`, even when you only expose a fixed agent — return honest empty lists and disable capabilities you do not support.

Full signatures are on [Server contract](/ui-sdk/setup-custom-servers/server-contract#agentbuilderserver).

## Capabilities

`getCapabilities` tells the UI which optional features your backend supports, so it can hide what you do not offer rather than surfacing controls that fail.

```ts
async getCapabilities() {
return {
data: {
sandbox: { enabled: false },
skill: { enabled: true },
// settings: { enabled: false }, // hides Settings even when catalog is attached
},
};
}
```

It is fetched once when the server resolves. `skill.reason` is shown when skills are disabled. Read the resolved value in your own components with [`useServerCapabilities()`](/ui-sdk/reference/hooks).

## Pickers

These methods feed the composer selectors. They are **not** the same as [catalog](/ui-sdk/setup-custom-servers/catalog) CRUD — catalog manages Settings; pickers list what an agent can attach right now.

| Method | Returns |
| --- | --- |
| `getModels` | `ModelSelection[]` — `id`, `name`, `provider`, `properties` |
| `getSkills` | `AgentSkill[]` — `id`, `name`, optional `description` |
| `getMcp` | `ConnectorState[]` — `id`, `name`, optional auth flags |

Return a non-empty `properties.reasoningEfforts` on a `ModelSelection` and the UI shows a reasoning-effort picker beside the model selector.

## Agent library

| Method | Role |
| --- | --- |
| `searchAgents` | Search / list library entries (`query?`, `limit?`, `offset?`) |
| `saveAgent` | Create or update (`intent: "create" \| "update"`) |
| `deleteAgent?` | Optional — omit to hide delete |

```ts
async searchAgents({ query, limit, offset } = {}) {
return [
{
agentId: "support-agent",
name: "Support agent",
// agentSpec: { ... } // supply to enable Edit; omit for try-only
},
];
}

async saveAgent({ agentName, agentSpec, intent, sessionId }) {
// persist; return { agentId?, sessionUpdatedAt? }
return { agentId: agentName };
}
```

On `AgentLibraryEntry`, `agentId` is the stable identifier used for selection, history filtering, and session binding; omit it and the row falls back to `name`.

## Chat with a library agent

How the shell exposes library vs composer is controlled by `agentConfig` on `TrueforgeUI` — see [Agent modes](/ui-sdk/guides/agent-modes). Creating a session with `agentName` (or binding a mutable `agentSpec`) is what ties chat to a library entry; the builder methods above only populate the pickers and save flow.

## Next

<CardGroup cols={2}>
<Card title="Putting it together" icon="layer-group" href="/ui-sdk/setup-custom-servers/putting-it-together">
Compose chat, builder, and catalog.
</Card>

<Card title="Server contract" icon="file-code" href="/ui-sdk/setup-custom-servers/server-contract">
`AgentSpec`, save request, and picker row types.
</Card>
</CardGroup>
85 changes: 85 additions & 0 deletions docs/ui-sdk/setup-custom-servers/catalog.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
title: "Catalog"
description: "Attach a CatalogServer so Settings can manage models, connectors, skills, and sandboxes."
---

`catalog` is the optional fourth part of an [`AgentUIServer`](/ui-sdk/setup-custom-servers/server-contract). Attach it and the settings UI appears; omit it and those surfaces stay hidden.

```ts
interface CatalogServer {
modelCatalog: ModelCatalogServer;
connectorCatalog: ConnectorCatalogServer;
skillCatalog?: SkillCatalogServer;
sandboxCatalog?: SandboxCatalogServer;
}
```

Models and connectors are required; skills and sandboxes are optional — omit either when your product has no such settings page.

Two conventions recur across all four. Every catalog exposes a **discovery** list of things the user could add (`get*Catalog`) alongside a list of what they have already configured (`list*`). And public read shapes never carry secrets — `apiKey` is accepted on writes and never returned.

Full method and DTO shapes are on [Settings catalog](/ui-sdk/reference/catalog).

| Sub-port | Settings surface |
| --- | --- |
| `modelCatalog` | Model providers and models |
| `connectorCatalog` | MCP connectors (including auth / disconnect) |
| `skillCatalog?` | Skills registry |
| `sandboxCatalog?` | Sandbox providers |

`getCapabilities().data.settings.enabled` can hide the settings control even when a `catalog` is attached — see [Capabilities](/ui-sdk/setup-custom-servers/server-contract#capabilities).

## Attach catalog to your server

```ts
import type { AgentUIServer, CatalogServer } from "@truefoundry/trueforge-ui";

const catalog: CatalogServer = {
modelCatalog: {
getModelProviderCatalog: async () => [],
listModelProviders: async () => [],
createModelProvider: async (req) => {
/* persist and return public shape */
throw new Error("unimplemented");
},
updateModelProvider: async (req) => {
throw new Error("unimplemented");
},
},
connectorCatalog: {
getConnectorCatalog: async () => [],
listConnectors: async () => [],
createConnector: async (req) => {
throw new Error("unimplemented");
},
updateConnector: async (req) => {
throw new Error("unimplemented");
},
authenticateConnector: async (req) => {
throw new Error("unimplemented");
},
disconnectConnector: async (req) => {
throw new Error("unimplemented");
},
},
};

const server: AgentUIServer = {
...chatAndBuilder,
catalog,
};
```

The stubs above are enough to show the Settings shell; fill in persistence as you add each surface. On `type: "trueforge"`, the same `catalog` field overrides the adapter defaults — see [Connect with TrueForge](/ui-sdk/setup-custom-servers/connect-with-trueforge#custom-catalog).

## Next

<CardGroup cols={2}>
<Card title="Agents" icon="robot" href="/ui-sdk/setup-custom-servers/agents">
Builder pickers are separate from catalog CRUD.
</Card>

<Card title="Settings catalog" icon="book" href="/ui-sdk/reference/catalog">
Full `CatalogServer` reference.
</Card>
</CardGroup>
Loading