From f006b4bebb59f20b012460b25a7a541756ff013f Mon Sep 17 00:00:00 2001 From: Govinda Vashishtha <57435703+govindavashishtha@users.noreply.github.com> Date: Thu, 13 Aug 2026 20:28:18 +0530 Subject: [PATCH] docs(ui-sdk): expand Server Customisations guides Add Overview, Connect with TrueForge, and a Bring your own server group covering concepts, chat, catalog, agents, and composition, and fix broken internal links. Co-authored-by: Cursor --- docs/docs.json | 14 ++- docs/ui-sdk/concepts/architecture.mdx | 4 +- docs/ui-sdk/get-started/quickstart.mdx | 2 + docs/ui-sdk/guides/troubleshooting.mdx | 4 +- docs/ui-sdk/reference/atoms.mdx | 6 +- docs/ui-sdk/reference/catalog.mdx | 4 +- docs/ui-sdk/reference/events.mdx | 8 +- docs/ui-sdk/reference/hooks.mdx | 4 +- docs/ui-sdk/reference/server.mdx | 4 +- docs/ui-sdk/reference/theme.mdx | 4 +- docs/ui-sdk/reference/trueforge-ui.mdx | 6 +- docs/ui-sdk/setup-custom-servers/agents.mdx | 81 ++++++++++++++++ docs/ui-sdk/setup-custom-servers/catalog.mdx | 85 ++++++++++++++++ docs/ui-sdk/setup-custom-servers/chat.mdx | 94 ++++++++++++++++++ .../connect-with-trueforge.mdx | 96 +++++++++++++++++++ .../connect-with-truefoundry.mdx | 76 ++------------- .../setup-custom-servers/core-concepts.mdx | 82 ++++++++++++++++ .../setup-custom-servers/custom-server.mdx | 57 ++++++----- docs/ui-sdk/setup-custom-servers/overview.mdx | 90 +++++++++++++++++ .../putting-it-together.mdx | 89 +++++++++++++++++ .../setup-custom-servers/server-contract.mdx | 12 ++- .../ui-sdk/setup-custom-ui/slot-overrides.mdx | 2 +- 22 files changed, 702 insertions(+), 122 deletions(-) create mode 100644 docs/ui-sdk/setup-custom-servers/agents.mdx create mode 100644 docs/ui-sdk/setup-custom-servers/catalog.mdx create mode 100644 docs/ui-sdk/setup-custom-servers/chat.mdx create mode 100644 docs/ui-sdk/setup-custom-servers/connect-with-trueforge.mdx create mode 100644 docs/ui-sdk/setup-custom-servers/core-concepts.mdx create mode 100644 docs/ui-sdk/setup-custom-servers/overview.mdx create mode 100644 docs/ui-sdk/setup-custom-servers/putting-it-together.mdx diff --git a/docs/docs.json b/docs/docs.json index 08e484bbe..177b39c7c 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -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" ] }, diff --git a/docs/ui-sdk/concepts/architecture.mdx b/docs/ui-sdk/concepts/architecture.mdx index d78b785de..66f61fef3 100644 --- a/docs/ui-sdk/concepts/architecture.mdx +++ b/docs/ui-sdk/concepts/architecture.mdx @@ -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 @@ -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. \ No newline at end of file +For token-level changes, prefer [theming](/ui-sdk/setup-custom-ui/custom-theme) over CSS overrides. \ No newline at end of file diff --git a/docs/ui-sdk/get-started/quickstart.mdx b/docs/ui-sdk/get-started/quickstart.mdx index 0dde55e85..508542e51 100644 --- a/docs/ui-sdk/get-started/quickstart.mdx +++ b/docs/ui-sdk/get-started/quickstart.mdx @@ -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). + ![The TrueforgeUI component rendering an agent chat with an agent-steps panel and a streamed response](/images/agent-composer-with-library.png) diff --git a/docs/ui-sdk/guides/troubleshooting.mdx b/docs/ui-sdk/guides/troubleshooting.mdx index f64b853cd..f4f01e33e 100644 --- a/docs/ui-sdk/guides/troubleshooting.mdx +++ b/docs/ui-sdk/guides/troubleshooting.mdx @@ -79,7 +79,7 @@ description: "Common failure modes and their causes." - 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). @@ -87,7 +87,7 @@ description: "Common failure modes and their causes." - 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. diff --git a/docs/ui-sdk/reference/atoms.mdx b/docs/ui-sdk/reference/atoms.mdx index b3ebc1f14..d81ffb94c 100644 --- a/docs/ui-sdk/reference/atoms.mdx +++ b/docs/ui-sdk/reference/atoms.mdx @@ -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 @@ -79,7 +79,7 @@ type ToolCallCardProps = { `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). Also `ToolCallContentBlock`, `ToolApprovalBar`, `ToolGroupCard`, `SubAgentCard`, @@ -115,5 +115,5 @@ theme and settings buttons. `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). diff --git a/docs/ui-sdk/reference/catalog.mdx b/docs/ui-sdk/reference/catalog.mdx index f522e138a..7e2689a36 100644 --- a/docs/ui-sdk/reference/catalog.mdx +++ b/docs/ui-sdk/reference/catalog.mdx @@ -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 @@ -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 { diff --git a/docs/ui-sdk/reference/events.mdx b/docs/ui-sdk/reference/events.mdx index 113ae791a..d494c9bf7 100644 --- a/docs/ui-sdk/reference/events.mdx +++ b/docs/ui-sdk/reference/events.mdx @@ -23,7 +23,7 @@ interface TurnStreamData { `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 @@ -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). These events also appear in `requiredActions` on a `done` turn state. That is how a turn that @@ -231,7 +231,7 @@ interface McpAuthRequiredEvent { 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 @@ -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) diff --git a/docs/ui-sdk/reference/hooks.mdx b/docs/ui-sdk/reference/hooks.mdx index 774aba9e1..9e8aff3bd 100644 --- a/docs/ui-sdk/reference/hooks.mdx +++ b/docs/ui-sdk/reference/hooks.mdx @@ -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 @@ -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 diff --git a/docs/ui-sdk/reference/server.mdx b/docs/ui-sdk/reference/server.mdx index 9abfde574..2985aabf6 100644 --- a/docs/ui-sdk/reference/server.mdx +++ b/docs/ui-sdk/reference/server.mdx @@ -83,5 +83,5 @@ to reference: -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). diff --git a/docs/ui-sdk/reference/theme.mdx b/docs/ui-sdk/reference/theme.mdx index fb55845fd..ac8361a97 100644 --- a/docs/ui-sdk/reference/theme.mdx +++ b/docs/ui-sdk/reference/theme.mdx @@ -47,7 +47,7 @@ type SlotOverrides = Partial; `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). diff --git a/docs/ui-sdk/reference/trueforge-ui.mdx b/docs/ui-sdk/reference/trueforge-ui.mdx index 8c2f4dc9b..e81c84cf2 100644 --- a/docs/ui-sdk/reference/trueforge-ui.mdx +++ b/docs/ui-sdk/reference/trueforge-ui.mdx @@ -192,13 +192,13 @@ import { TrueforgeUI } from "@truefoundry/trueforge-ui"; - See [Theming](/ui-sdk/guides/theming). + See [Theming](/ui-sdk/setup-custom-ui/custom-theme). Replace any built-in component. `Partial`, 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). @@ -228,7 +228,7 @@ Persisted sessions remain available through the thread list. 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). ## Example diff --git a/docs/ui-sdk/setup-custom-servers/agents.mdx b/docs/ui-sdk/setup-custom-servers/agents.mdx new file mode 100644 index 000000000..f061c5053 --- /dev/null +++ b/docs/ui-sdk/setup-custom-servers/agents.mdx @@ -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 + + + + Compose chat, builder, and catalog. + + + + `AgentSpec`, save request, and picker row types. + + diff --git a/docs/ui-sdk/setup-custom-servers/catalog.mdx b/docs/ui-sdk/setup-custom-servers/catalog.mdx new file mode 100644 index 000000000..556c9d55c --- /dev/null +++ b/docs/ui-sdk/setup-custom-servers/catalog.mdx @@ -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 + + + + Builder pickers are separate from catalog CRUD. + + + + Full `CatalogServer` reference. + + diff --git a/docs/ui-sdk/setup-custom-servers/chat.mdx b/docs/ui-sdk/setup-custom-servers/chat.mdx new file mode 100644 index 000000000..04096b9a9 --- /dev/null +++ b/docs/ui-sdk/setup-custom-servers/chat.mdx @@ -0,0 +1,94 @@ +--- +title: "Chat" +description: "Implement AgentChatServer — sessions, turns, history, cancel, and resume." +--- + +`AgentChatServer` is the runtime the chat UI calls. All operations are keyed by a flat `sessionId`. Method signatures live on [Server contract](/ui-sdk/setup-custom-servers/server-contract#agentchatserver); this page is the cookbook. + +## Sessions + +| Method | Role | +| --- | --- | +| `createSession` | Open a conversation (`agentName?`, `agentSpec?`, `title?`) | +| `listSessions` | Paginated session list for the thread sidebar | +| `getSession` | Load one session by id | +| `updateSession` | Update title or mutable agent spec | +| `deleteSession?` | Optional — omit to hide delete in the session list | + +```ts +async createSession({ agentName, agentSpec, title } = {}) { + return { + id: crypto.randomUUID(), + agentName: agentName ?? null, + agentSpec, + title: title ?? null, + isMutable: agentSpec != null, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }; +} +``` + +List methods return `{ data, nextPageToken? }` — see [Pagination](/ui-sdk/setup-custom-servers/custom-server#pagination) on the landing page. + +## Turns + +| Method | Role | +| --- | --- | +| `createTurn` | Start a turn and stream `{ sequenceNumber, event }` envelopes | +| `listTurns` | Paginated turns in a session | +| `getTurn` | Load one turn (state, input, timestamps) | +| `cancelSession` | Cancel the in-flight turn for a session | + +`createTurn` accepts `input?: TurnInputItem[]` — a plain chat message, a tool approval, or a tool response. Branch on `type` as described in [Turn input](/ui-sdk/setup-custom-servers/server-contract#turn-input). + +The minimum stream is covered on [Bring your own server](/ui-sdk/setup-custom-servers/custom-server#streaming). For tool calls, approvals, threads, and sandboxes, implement the shapes in [Streaming events](/ui-sdk/reference/events). + +```ts +async *createTurn({ sessionId, input, abortSignal }) { + let seq = 0; + for await (const event of myBackendStream({ sessionId, input, abortSignal })) { + yield { sequenceNumber: seq++, event }; + } +} +``` + +## Resume a live turn + +`subscribeToTurn` is optional. When present, a reconnecting client passes the last `sequenceNumber` it saw as `afterSequenceNumber`, and you replay only what follows — not the whole turn. + +```ts +async *subscribeToTurn({ sessionId, turnId, afterSequenceNumber, abortSignal }) { + let seq = (afterSequenceNumber ?? -1) + 1; + for await (const event of myResumeStream({ sessionId, turnId, afterSequenceNumber, abortSignal })) { + yield { sequenceNumber: seq++, event }; + } +} +``` + +Pass the same `abortSignal` you use on `createTurn` to tear the subscription down. + +## History + +| Method | Role | +| --- | --- | +| `listEvents` | Hydrate session history (`pageToken?`, `lastTurnId?`, `limit?`) | +| `listTurnEvents?` | Optional — events for a single in-flight turn when your backend can serve them per turn | + +`listEvents` returns session-level wrappers that identify the turn; see [Streaming events](/ui-sdk/reference/events#the-unions) for how history differs from the live stream (no deltas — the assembled `model.message` is stored instead). + +## Sandbox downloads + +`downloadSandboxFile` is optional. Return a `Blob` when agents produce artifacts users should download. It receives both `turnId` and `sandboxId` because backends address sandboxes differently — see the note on [Server contract](/ui-sdk/setup-custom-servers/server-contract#agentchatserver). + +## Next + + + + Attach settings catalogs. + + + + Builder pickers and the agent library. + + diff --git a/docs/ui-sdk/setup-custom-servers/connect-with-trueforge.mdx b/docs/ui-sdk/setup-custom-servers/connect-with-trueforge.mdx new file mode 100644 index 000000000..85cec7df3 --- /dev/null +++ b/docs/ui-sdk/setup-custom-servers/connect-with-trueforge.mdx @@ -0,0 +1,96 @@ +--- +title: "Connect with TrueForge" +description: "Point TrueforgeUI at a TrueForge server" +--- + +Point `TrueforgeUI` at a TrueForge server. The SDK builds the HTTP client, and composes chat + builder + default settings catalogs into an `AgentUIServer`. + + +## Render against TrueForge + +Omit `baseUrl` to talk same-origin (or through a reverse proxy). Pass an absolute URL when the UI and harness are on different origins. + +```tsx App.tsx +import { TrueforgeUI } from "@truefoundry/trueforge-ui"; + +export default function App() { + return ( +
+ +
+ ); +} +``` + +Because this config is resolved asynchronously, the SDK shows a brief loading indicator before the chat appears. + + +## Auth + +How the UI authenticates to TrueForge is separate from whether the **server** itself requires login. + +| Approach | When to use | +| --- | --- | +| Omit `token` and `fetch` | Same-origin or a proxy that already attaches credentials | +| `token` | Bearer auth for embeds and remote APIs | +| Custom `fetch` | Cookie sessions, OIDC-aware hosts, or other request interceptors | + +**Bearer token:** + +```tsx + +``` + +**Cookie / same-origin hosts** — omit `token` and inject `fetch` (for example an auth-aware wrapper that follows OIDC cookies): + +```tsx + +``` + +To leave login off on the TrueForge server, or to turn on OIDC for a shared deployment, see [Setup Login](/authentication/overview). That page covers server-side configuration; this page only covers how the UI SDK sends credentials. + +## Custom catalog + +Pass `catalog` to override the adapter's default settings catalogs. Without it, those Settings surfaces use the built-in catalogs from the TrueForge adapter (when the server exposes them). Supplying your own `CatalogServer` replaces that default. + +```tsx +import type { CatalogServer } from "@truefoundry/trueforge-ui"; + +const catalog: CatalogServer = { + modelCatalog: { + /* ... */ + }, + connectorCatalog: { + /* ... */ + }, + // skillCatalog and sandboxCatalog are optional +}; + + +``` + +The full port — model providers, connectors, skills, and sandboxes — is on [Settings catalog](/ui-sdk/reference/catalog). For a hand-written server that attaches catalog the same way, see [Catalog](/ui-sdk/setup-custom-servers/catalog) under Bring your own server. diff --git a/docs/ui-sdk/setup-custom-servers/connect-with-truefoundry.mdx b/docs/ui-sdk/setup-custom-servers/connect-with-truefoundry.mdx index 6b6bf5721..76d2456f2 100644 --- a/docs/ui-sdk/setup-custom-servers/connect-with-truefoundry.mdx +++ b/docs/ui-sdk/setup-custom-servers/connect-with-truefoundry.mdx @@ -1,8 +1,11 @@ --- title: "Connect with TrueFoundry" +description: "Point TrueforgeUI at TrueFoundry Control Plane + Gateway, or compose hosted chat with your own builder." --- -The zero-config path. The SDK builds the agent UI server from your API key and control plane URL; the gateway URL is optional and resolved from the control plane when omitted. +The zero-config path for TrueFoundry. For TrueForge or a hand-written `AgentUIServer`, see [Overview](/ui-sdk/setup-custom-servers/overview). + +The SDK builds the agent UI server from your API key and control plane URL; the gateway URL is optional and resolved from the control plane when omitted. ```jsx App.tsx import { TrueforgeUI } from "@truefoundry/trueforge-ui"; @@ -16,7 +19,6 @@ export default function App() { apiKey: {{API_KEY}}, controlPlaneURL: {{CONTROL_PLANE_URL}}, }} - layout="sidebar" /> ); @@ -25,76 +27,10 @@ export default function App() { Add `gatewayPlaneURL` alongside `controlPlaneURL` to target a specific gateway. -Because this config is resolved asynchronously, the SDK shows a brief loading indicator before the chat appears. The other two paths mount immediately. - -## Build the server yourself - -If you need to hold the resolved `AgentUIServer` — to wrap it, log through it, or pass it around before mounting — build it with `createTrueFoundryAgentUIServer`. It returns a ready server (gateway chat plus the Control Plane builder lists) that you hand to `server` directly, so there is no async resolution and no loading indicator on mount. - -```tsx App.tsx -import { useEffect, useState } from "react"; -import { TrueforgeUI } from "@truefoundry/trueforge-ui"; -import { - createTrueFoundryAgentUIServer, - type TrueFoundryAgentUIServer, -} from "@truefoundry/assistant-ui-runtime/plugins/truefoundry-agent-server-adapter"; - -export default function App() { - const [server, setServer] = useState(null); - - useEffect(() => { - createTrueFoundryAgentUIServer({ - apiKey: import.meta.env.VITE_TFY_API_KEY, - cpURL: import.meta.env.VITE_TFY_CONTROL_PLANE_URL, - }).then(setServer); - }, []); - - if (server === null) { - return null; - } - - return ( -
- -
- ); -} -``` - -`gatewayURL` is optional — when omitted it is resolved from `cpURL`. - -## TrueFoundry chat, your own builder +{/* TODO: Add links for connecting to TrueFoundry and creating an account. */} -To keep TrueFoundry's hosted chat streaming but serve the builder surfaces — models, skills, connectors, and the agent library — from your own backend, compose the gateway chat port with your callbacks through `createTrueFoundryServer`. The stubs below return empty lists, which is enough to mount; fill them in as you add agent management. - -```jsx App.tsx -import { TrueforgeUI, createTrueFoundryServer } from "@truefoundry/trueforge-ui"; -import { createTrueFoundryChatServer } from "@truefoundry/assistant-ui-runtime/plugins/truefoundry-agent-server-adapter"; - -const chatServer = createTrueFoundryChatServer({ - apiKey: import.meta.env.VITE_TFY_API_KEY, - baseUrl: import.meta.env.VITE_TFY_GATEWAY_URL, -}); +Because this config is resolved asynchronously, the SDK shows a brief loading indicator before the chat appears. The other two paths mount immediately. -const server = createTrueFoundryServer({ - chatServer, - getCapabilities: async () => ({ - data: { sandbox: { enabled: false }, skill: { enabled: false } }, - }), - getModels: async () => [], - getSkills: async () => [], - getMcp: async () => [], - searchAgents: async () => [], - saveAgent: async () => ({}), -}); -export default function App() { - return ( -
- -
- ); -} -``` To own chat streaming as well — every call, including the `createTurn` event stream, served by your backend — implement the full interface instead: [Bring your own server](/ui-sdk/setup-custom-servers/custom-server). \ No newline at end of file diff --git a/docs/ui-sdk/setup-custom-servers/core-concepts.mdx b/docs/ui-sdk/setup-custom-servers/core-concepts.mdx new file mode 100644 index 000000000..bb443e566 --- /dev/null +++ b/docs/ui-sdk/setup-custom-servers/core-concepts.mdx @@ -0,0 +1,82 @@ +--- +title: "Core concepts" +description: "Sessions, turns, and the event families a custom AgentUIServer must speak." +--- + +The UI only speaks [`AgentUIServer`](/ui-sdk/setup-custom-servers/server-contract). Your backend can be TrueForge HTTP, a BFF, or something else — as long as it implements the port and emits event shapes the UI folds into a transcript. + +Interaction follows **Agent → Session → Turn → Event → Delta**. The product [SDK Overview](/api/overview) walks that hierarchy with a running example; this page maps each layer to the methods `TrueforgeUI` calls. + +| Layer | What it is | UI methods | +| --- | --- | --- | +| **Agent** | A saved definition (model, tools, config) — not a running process | Builder: `searchAgents`, `saveAgent`; sessions may carry `agentName` / `agentSpec` | +| **Session** | One conversation / issue | `createSession`, `listSessions`, `getSession`, `updateSession` | +| **Turn** | One request boundary (message, approval, or tool response) | `createTurn`, `listTurns`, `getTurn`, `cancelSession` | +| **Event** | What the stream (and history) record | Yielded from `createTurn` / `subscribeToTurn`; hydrated via `listEvents` | +| **Delta** | Incremental chunks that merge into a parent event by `id` | e.g. `model.message.delta` → `model.message` | + +Full signatures are on [Server contract](/ui-sdk/setup-custom-servers/server-contract). The stream protocol is on [Streaming events](/ui-sdk/reference/events). + +## Sessions + +A session is one conversation context. Persist its `id` so the user can return later. Only one turn runs inside a session at a time. + +`Session` requires `id`, `isMutable`, `createdAt`, and `updatedAt` (ISO strings). Set `isMutable: true` while the agent spec may still be edited — that is what permits `updateSession`. + +## Turns + +A turn is one back-and-forth boundary. Each user message, approval, or tool response is a new `createTurn` call. Turns chain via `previousTurnId` (often `"auto"` on TrueForge); the agent sees earlier turns without you resending history. + +Input arrives as [`TurnInputItem`](/ui-sdk/setup-custom-servers/server-contract#turn-input): `user.message`, `user.tool_approval`, or `user.tool_response`. Branch on `type`. + +A turn ends in `done`, `cancelled`, or `error`. A `done` turn may still carry `requiredActions` — that means it is waiting on the user, not finished outright. + +## Events + +`createTurn` yields `{ sequenceNumber, event }` envelopes. `sequenceNumber` must increase monotonically within the turn so [`subscribeToTurn`](/ui-sdk/setup-custom-servers/server-contract#agentchatserver) can resume from `afterSequenceNumber`. + +### Lifecycle + +Every turn is bracketed by `turn.created` and exactly one `turn.done`. A stream that ends without `turn.done` leaves the UI showing the turn as still running. + +### Content + +| Event | Role | +| --- | --- | +| `model.message` | A complete assistant message | +| `model.message.delta` | Incremental text — the _increment_, not the running total; reuse one `id` across deltas for the same message | + +### Pausing for the user + +| Event | User reply on the next `createTurn` | +| --- | --- | +| `tool.approval_required` | `user.tool_approval` | +| `tool.response_required` | `user.tool_response` (ask-user questions) | +| `mcp.auth_required` | Complete OAuth, then start the next turn — see [MCP OAuth](/ui-sdk/setup-custom-ui/mcp-oauth) | + +These pause events also appear in `requiredActions` on a `done` turn state. + +### MCP, sandbox, and sub-agents + +| Event | Role | +| --- | --- | +| `mcp.initialize` | MCP servers connected for the thread | +| `tool.response` | Result of a tool call | +| `sandbox.created` | Sandbox provisioned — use `sandboxId` with optional `downloadSandboxFile` | +| `thread.created` / `thread.done` | Sub-agent threads; the UI groups events by `threadId` | + +### Generative UI + +Generative UI is enabled on the agent via `config` (for example `generativeUi.enabled` on [`AgentSpec`](/ui-sdk/setup-custom-servers/server-contract#agentspec)) and rendered from message content. For how TrueForge authors it, see [Generative UI](/create-agent/generative-ui) — do not reinvent a parallel protocol in the UI SDK. + +## Next + + + + Implement session and turn operations. + + + + Full event shapes and unions. + + diff --git a/docs/ui-sdk/setup-custom-servers/custom-server.mdx b/docs/ui-sdk/setup-custom-servers/custom-server.mdx index 7c68afb20..9ce3368a5 100644 --- a/docs/ui-sdk/setup-custom-servers/custom-server.mdx +++ b/docs/ui-sdk/setup-custom-servers/custom-server.mdx @@ -3,14 +3,10 @@ title: "Bring your own server" description: "Implement AgentUIServer and pass the object straight to the component." --- -Use this when your backend owns the whole contract — sessions, chat streaming, and the agent builder. You implement `AgentUIServer` and pass the object straight to the component, with no `type` wrapper: every call the UI makes, including the `createTurn` event stream, hits your endpoints. Nothing here depends on TrueFoundry. +Use this when your backend owns the whole contract — sessions, chat streaming, and the agent builder. You implement `AgentUIServer` and pass the object straight to the component, every call the UI makes, including the `createTurn` event stream, hits your endpoints. Because `server` accepts an `AgentUIServer` directly, you can front any backend — including your own proxy that keeps API keys server-side. The object is used immediately, so there is no loading indicator on mount. - - To keep TrueFoundry's hosted chat and supply only your own builder callbacks, use the composition helpers on [Connect with TrueFoundry](/ui-sdk/setup-custom-servers/connect-with-truefoundry#truefoundry-chat-your-own-builder) instead. This page assumes your backend serves everything. - - ## Minimal implementation The shape below is the smallest thing that mounts. Optional methods are omitted; required ones must exist even if they only throw in paths your UI never reaches. @@ -92,7 +88,7 @@ export const server: AgentUIServer = { Declaring `sandbox` and `skill` as disabled is the honest starting point — the UI then hides those affordances instead of offering controls your backend cannot serve. Flip them on as you implement each. ```tsx title="App.tsx" - + ``` ## Streaming @@ -141,7 +137,7 @@ async *createTurn({ sessionId, input }) { Two things are easy to get wrong. Deltas carry the _increment_ rather than the accumulated text, and every delta for one message shares a single `id`. And a stream that ends without a `turn.done` leaves the UI showing the turn as still running. -[Streaming events](/ui-sdk/reference/events) documents the full protocol — tool calls, approval prompts, sub-agent threads, and sandbox artifacts. +[Streaming events](/ui-sdk/reference/events) documents the full protocol — tool calls, approval prompts, sub-agent threads, and sandbox artifacts. For how sessions, turns, and events fit together, see [Core concepts](/ui-sdk/setup-custom-servers/core-concepts). ## Pagination @@ -179,33 +175,42 @@ Spreading `nextPageToken` in only when present keeps the result valid under `exa - Attach a [`CatalogServer`](/ui-sdk/reference/catalog) to enable the settings UI — models, connectors, skills, and sandboxes. Without it those surfaces do not render. + Attach a [`CatalogServer`](/ui-sdk/reference/catalog) to enable the settings UI — models, connectors, skills, and sandboxes. Without it those surfaces do not render. See [Catalog](/ui-sdk/setup-custom-servers/catalog). -## Widening the types +## Attachments -The interfaces are generic so you can carry backend-specific fields through the UI without casting. `AgentUIServer` itself is a plain alias, so compose the widened chat and builder ports directly: +Attachment handling defaults to `trueFoundryAttachmentAdapter`. Override it through the `adapters` prop on `TrueforgeUI` if your backend stores uploads differently. -```ts -interface MyModel extends ModelSelection { - modelId: string; -} +```tsx + +``` -type MySkillMount = { fqn: string; preload: boolean }; -type MySpec = AgentSpec; +## What's next -const server: AgentChatServer & AgentBuilderServer = { - /* ... */ -}; -``` + + + Sessions, turns, and the event families the UI understands. + -See [Widening the types](/ui-sdk/setup-custom-servers/server-contract#widening-the-types) for the full set of parameters. + + Session and turn operations on `AgentChatServer`. + -## Attachments + + Attach settings catalogs for models, connectors, skills, and sandboxes. + -Attachment handling defaults to `trueFoundryAttachmentAdapter`. Override it through the `adapters` prop on `TrueforgeUI` if your backend stores uploads differently. + + Builder pickers, capabilities, and the agent library. + -```tsx - -``` \ No newline at end of file + + Compose chat, builder, and catalog into one server. + + + + Full method signatures and type widening. + + diff --git a/docs/ui-sdk/setup-custom-servers/overview.mdx b/docs/ui-sdk/setup-custom-servers/overview.mdx new file mode 100644 index 000000000..ae9764e18 --- /dev/null +++ b/docs/ui-sdk/setup-custom-servers/overview.mdx @@ -0,0 +1,90 @@ +--- +title: "Overview" +description: "Choose how TrueforgeUI talks to a backend: TrueForge, TrueFoundry, or your own AgentUIServer." +--- + +The `server` prop accepts a built-in config object or an object implementing `AgentUIServer`. TrueForge is the default path for a self-hosted harness; TrueFoundry wires Control Plane + Gateway; a hand-written `AgentUIServer` is used when your backend owns the whole contract. + +```ts +type TrueforgeServerConfig = + | { + type: "trueforge"; + baseUrl?: string; + token?: string; + fetch?: typeof fetch; + catalog?: CatalogServer; + } + | { + type: "truefoundry"; + apiKey: string; + controlPlaneURL: string; + gatewayPlaneURL?: string; + catalog?: CatalogServer; + } + | AgentUIServer; +``` + +There is no `type: "custom"` — pass the `AgentUIServer` object directly. + + + Built-in configs (`trueforge` / `truefoundry`) resolve asynchronously, so the SDK renders a brief loading indicator first. An `AgentUIServer` object is used immediately and mounts without that delay. + + +## TrueForge (default) + +Point `TrueforgeUI` at a TrueForge server. Omit `baseUrl` to talk same-origin; pass `token` or a custom `fetch` when the host owns auth. + +```tsx + +``` + +See [Connect with TrueForge](/ui-sdk/setup-custom-servers/connect-with-trueforge). + +## TrueFoundry + +The SDK builds the agent UI server from your API key and control plane URL. + +```tsx + +``` + +See [Connect with TrueFoundry](/ui-sdk/setup-custom-servers/connect-with-truefoundry). + +## Bring your own server + +Implement `AgentUIServer` and pass the object straight to the component — every call the UI makes, including the `createTurn` event stream, hits your endpoints. + +```tsx + +``` + +Start with [Bring your own server](/ui-sdk/setup-custom-servers/custom-server). The typed contract lives on [Server contract](/ui-sdk/setup-custom-servers/server-contract). + + + + Default harness path — auth and optional catalog overrides. + + + + Control Plane + Gateway, or chat from TrueFoundry with your own builder. + + + + Implement `AgentUIServer` and pass it straight to `TrueforgeUI`. + + + + Chat, builder, and catalog method signatures. + + diff --git a/docs/ui-sdk/setup-custom-servers/putting-it-together.mdx b/docs/ui-sdk/setup-custom-servers/putting-it-together.mdx new file mode 100644 index 000000000..4ddfb69ff --- /dev/null +++ b/docs/ui-sdk/setup-custom-servers/putting-it-together.mdx @@ -0,0 +1,89 @@ +--- +title: "Putting it together" +description: "Compose chat, builder, and catalog into a complete AgentUIServer." +--- + +An `AgentUIServer` is chat and builder, plus an optional settings catalog: + +```ts +type AgentUIServer = AgentChatServer & AgentBuilderServer & { catalog?: CatalogServer }; +``` + +Build it in layers. Each step mounts; add the next when your backend can serve it. + +## 1. Chat-only stub + +Implement the [minimal chat + builder surface](/ui-sdk/setup-custom-servers/custom-server#minimal-implementation) so `TrueforgeUI` mounts. Disable sandbox and skills in `getCapabilities` until those paths exist. Empty `searchAgents` / `getSkills` / `getMcp` is fine for a first chat. + +## 2. Add builder callbacks + +Fill `getModels`, `getSkills`, `getMcp`, `searchAgents`, and `saveAgent` so the composer and library work. See [Agents](/ui-sdk/setup-custom-servers/agents). + +## 3. Attach catalog + +Add a [`CatalogServer`](/ui-sdk/setup-custom-servers/catalog) when Settings should manage providers and connectors: + +```ts +const server: AgentUIServer = { + ...chatServerMethods, + ...builderMethods, + catalog, +}; +``` + +```tsx + +``` + +## End-to-end sketch + +```ts +import type { + AgentBuilderServer, + AgentChatServer, + AgentUIServer, + CatalogServer, +} from "@truefoundry/trueforge-ui"; + +const chat: AgentChatServer = { + /* createSession, listSessions, getSession, updateSession, + createTurn, cancelSession, listTurns, getTurn, listEvents */ +}; + +const builder: AgentBuilderServer = { + /* getCapabilities, getModels, getSkills, getMcp, searchAgents, saveAgent */ +}; + +const catalog: CatalogServer = { + modelCatalog: { + /* ... */ + }, + connectorCatalog: { + /* ... */ + }, +}; + +export const server: AgentUIServer = { + ...chat, + ...builder, + catalog, +}; +``` + +Widen types when your backend returns richer rows — see [Widening the types](/ui-sdk/setup-custom-servers/server-contract#widening-the-types). + + + To keep TrueFoundry's hosted chat streaming but serve builder surfaces from your own backend, compose with `createTrueFoundryServer` instead of hand-writing chat — [TrueFoundry chat, your own builder](/ui-sdk/setup-custom-servers/connect-with-truefoundry#truefoundry-chat-your-own-builder). + + +## Next + + + + Every method signature. + + + + TrueForge, TrueFoundry, or bring your own. + + diff --git a/docs/ui-sdk/setup-custom-servers/server-contract.mdx b/docs/ui-sdk/setup-custom-servers/server-contract.mdx index 95700c0b4..910cdabf7 100644 --- a/docs/ui-sdk/setup-custom-servers/server-contract.mdx +++ b/docs/ui-sdk/setup-custom-servers/server-contract.mdx @@ -315,15 +315,23 @@ const server: AgentChatServer & AgentBuilderServer = { }; ``` -The UI keeps reading only the fields it knows about; your own components — supplied through [slot overrides](/ui-sdk/guides/slot-overrides) — can read the rest. +The UI keeps reading only the fields it knows about; your own components — supplied through [slot overrides](/ui-sdk/setup-custom-ui/slot-overrides) — can read the rest. ## Next - + + TrueForge, TrueFoundry, or bring your own. + + + A minimal `AgentUIServer` you can copy. + + Compose chat, builder, and catalog. + + The event protocol `createTurn` yields. diff --git a/docs/ui-sdk/setup-custom-ui/slot-overrides.mdx b/docs/ui-sdk/setup-custom-ui/slot-overrides.mdx index bc15fc320..144e52225 100644 --- a/docs/ui-sdk/setup-custom-ui/slot-overrides.mdx +++ b/docs/ui-sdk/setup-custom-ui/slot-overrides.mdx @@ -91,7 +91,7 @@ honor the props you receive — several are rendered nodes (`actionBar`, `error` `Button` and `IconButton` publish their prop types for typing your own components. The buttons themselves are restyled through semantic tokens and CSS rather than replaced — see - [Theming](/ui-sdk/guides/theming). + [Theming](/ui-sdk/setup-custom-ui/custom-theme). ## Discovering slot names