Frontend SDK Reference

@ces/app-sdk is the supported frontend boundary for Cessy Custom Pages. The host provides it through the page import map, so page bundles import it directly and do not install or bundle an npm package.

For machine-readable discovery, call get_frontend_sdk through Design MCP or read ces://design/capabilities/frontend-sdk. Those surfaces expose the same platform-owned export contract summarized here.

Choose the correct boundary

NeedSupported boundary
Read projections or execute commands in a Custom PageuseProjection, useDocument, and useCommand
List app agents and build a page-owned assistant experienceuseAgents followed by useAgentChat
Chat in an existing channel or entity threaduseChannelChat
Build an external frontend or partner BFFThe app-specific Runtime REST OpenAPI, GET /agents, and channel endpoints

Do not hand-wire /api/apps/..., page-chat, attachment, workspace, or other platform-internal routes. They are host implementation details, not public integration contracts. Custom Pages use the SDK; external clients fetch the app-specific OpenAPI document and use Runtime REST.

Host context, authentication, and runtime source

Cessy mounts each hosted page inside CesPageProvider. The host supplies the tenant and app identity, current user, page parameters and binding, navigation, an authenticated fetch function, and the selected runtime source.

Page code never receives or stores a bearer token. Data, command, file, useAgents, and channel-chat helpers preserve the provider’s Production or Workspace source. The shell selects that source; page code should not add workspaceId itself.

useAgentChat currently resolves its chat target from the published app configuration. useAgents can show a Workspace-only agent while previewing, but that agent becomes a valid useAgentChat target only after promotion. This limitation is also declared on the machine-readable SDK contract. Do not bypass it by calling an internal page-chat route.

useCesContext().fetch is an authenticated low-level fetch function, not a general public API client and not an automatic runtime-source URL rewriter. Prefer the typed SDK hooks. If a supported public HTTP operation is needed from an external client, use the generated Runtime REST contract instead.

User-delegated chat requires an authenticated operator. Do not assume that useAgentChat or useChannelChat is available to an anonymous public page share merely because projection or command access was granted to its constrained public principal.

Agent selection and page chat

useAgents returns only the safe app agent catalog. Each item has this shape:

1interface PublicAgentSummary {
2 id: string;
3 name: string;
4 label: string;
5 kind: 'standard';
6}
7
8interface UseAgentsResult {
9 agents: PublicAgentSummary[];
10 isLoading: boolean;
11 error: Error | null;
12 refresh: () => Promise<PublicAgentSummary[]>;
13}

The catalog does not expose prompts, models, MCP configuration, credentials, container settings, provider secrets, scope policy, or other private runtime configuration. In Production, or for an agent already present in the published configuration, a selected id can be passed directly to useAgentChat.

1import { useState } from 'react';
2import { useAgents, useAgentChat } from '@ces/app-sdk';
3import { Button } from '@app/ui/Button';
4import { Card } from '@app/ui/Card';
5import { Stack } from '@app/ui/Stack';
6
7function AgentConversation({ agentId }: { agentId: string }) {
8 const chat = useAgentChat({ agentId });
9
10 return (
11 <Card>
12 <Stack gap={8}>
13 {chat.messages.map((message) => (
14 <div key={message.id} data-role={message.role}>
15 {message.parts.map((part, index) =>
16 part.type === 'text' ? <p key={index}>{part.text}</p> : null
17 )}
18 </div>
19 ))}
20 <Button onClick={() => void chat.sendMessage('How can you help here?')}>Ask</Button>
21 </Stack>
22 </Card>
23 );
24}
25
26export default function AgentPicker() {
27 const { agents, isLoading, error, refresh } = useAgents();
28 const [agentId, setAgentId] = useState<string | null>(null);
29
30 if (isLoading) return <p>Loading agents…</p>;
31 if (error) {
32 return <Button onClick={() => void refresh()}>Retry agent catalog</Button>;
33 }
34
35 return (
36 <Stack gap={8}>
37 {agents.map((agent) => (
38 <Button key={agent.id} onClick={() => setAgentId(agent.id)}>
39 {agent.label}
40 </Button>
41 ))}
42 {agentId ? <AgentConversation agentId={agentId} /> : null}
43 </Stack>
44 );
45}

When useAgentChat has no active conversation, the first send creates a fresh channel-backed DM conversation. Selecting a conversation from its history continues that selected conversation. startNewConversation() clears the active selection so the next send creates another fresh conversation. The chat target remains the published agent configuration even while the surrounding page previews Workspace data.

Use useChannelChat instead when the channel itself is the domain conversation. It can bind by channelId or by an entity reference and will not create a parallel page-agent DM.

Value exports

ExportSignature or purpose
useProjectionuseProjection<T>(name, options?) reads a projection list or document through SWR.
useDocumentuseDocument<T>() reads the server-prefetched document for a bound page and returns a ready or error state.
useCommanduseCommand<T>(name) returns execute, isLoading, and error; execute resolves after related page caches revalidate.
useAdapterOperationuseAdapterOperation<T>(adapterName, operation) calls a configured adapter through the host boundary.
useAgentsuseAgents() loads the safe, source-aware app agent catalog.
useAuthuseAuth() returns the current CesUser or null.
useParamsuseParams() returns merged path and query parameters.
useCesNavigationReturns the app id plus currentSlug, navigateTo, and goBack.
useAssetUrlReturns a resolver for page deployment assets.
useFileUrlReturns a resolver for authenticated Platform file URLs.
useUploadFileReturns the authenticated Platform file upload function.
useBeforeRuntimeSourceSwitchRegisters a guard for dirty or in-flight page state before a source switch.
useAgentChatCreates or selects page-agent DM conversations against the published agent target and exposes history, AI SDK-compatible messages, streaming state, attachments, and page refresh state.
useChannelChatBinds to an existing channel or entity channel and exposes messages, binding/send state, attachments, and streaming state.
useCesContextReads the host context. Prefer the higher-level hooks for platform operations.
CesPageProviderHost integration component. Normal Custom Page code consumes it indirectly and should not mount a second provider.

ProjectionOptions supports id, filter, limit, offset, and fallbackData. useChannelChat accepts either channelId or entityRef; set createIfMissing only when explicitly creating an entity channel is intended.

Type exports

The module also exports these public TypeScript contracts:

  • data and actions: ProjectionOptions, UseDocumentResult, CommandPayload, UseCommandResult, UseAdapterOperationResult
  • agent catalog: PublicAgentSummary, UseAgentsResult
  • page chat: AgentChatActiveConversation, AgentChatAgent, AgentChatConversation, AgentChatMessage, AgentChatMessageMetadata, AgentChatPushStatus, AgentChatSendMessageInput, AgentChatSendResult, AgentChatUploadOptions, UseAgentChatOptions, UseAgentChatResult
  • channel chat: ChannelChatAgentOptions, ChannelChatBindingStatus, ChannelChatChannel, ChannelChatEntityRef, ChannelChatMessage, ChannelChatMessageMetadata, ChannelChatPushStatus, ChannelChatSendMessageInput, ChannelChatSendResult, ChannelChatSendStatus, ChannelChatUploadOptions, UseChannelChatOptions, UseChannelChatResult
  • page context and files: CesAdapterCallResponse, CesAdapterOperationInput, CesFileAccess, CesFileRef, CesFileRefInput, CesPageContext, CesUploadFileOptions, CesUser, ResolvedBinding

The hosted module is the runtime boundary. The public docs and Design MCP contract describe its types, but this work does not publish a standalone npm package or promise a local SDK development server.

External frontend and BFF equivalent

An external frontend cannot use @ces/app-sdk. Its server-side BFF should:

  1. fetch /api/rest/<tenant-id>/<app-id>/openapi
  2. list safe agent metadata with GET /api/rest/<tenant-id>/<app-id>/agents
  3. obtain a delegated OAuth token for the signed-in user
  4. create a fresh conversation with POST /channels/dm
  5. continue it through the returned channel id

The agent catalog uses normal Runtime REST authentication. Channel and user channel-view operations are user-delegated and reject API keys and agent service tokens. See BFF Pattern for the complete OAuth flow and Runtime API for the generated HTTP contract.