Agent SDK
Agent SDK overview
Choose the right Agent SDK package surface, understand the App Agent model, and start with the integration path that fits your product.
The Agent SDK gives you three integration styles:
- Drop-in web embed with
@emcy/agent-sdk/react-embed - Custom product UI with
@emcy/agent-sdk/reactor@emcy/agent-sdk/react-native - Low-level runtime access with
@emcy/agent-sdk
For most product teams, the public mental model to use is App Agent.
An App Agent owns:
- conversation lifecycle
- streaming and tool execution state
- connection status and MCP auth attention
- approvals
- structured input requests
- feedback submission state
- resume and stale-conversation recovery
Your app owns:
- layout and branding
- client tools
- app-specific context and prompt policy
- navigation and workspace visuals
Package map#
@emcy/agent-sdk#
Low-level runtime and transport:
EmcyAgent- core transport and message state
- core auth persistence helpers
- low-level types
Use this when you need raw runtime control or you are building a framework adapter.
@emcy/agent-sdk/app#
Framework-agnostic App Agent layer:
createAppAgentAppAgentController- shared presentation helpers
- browser storage helpers
- platform auth helper
Use this when you want the controller directly or when you are building on top of the shared agent-experience model outside React.
@emcy/agent-sdk/react#
React binding for custom product UIs:
useAppAgentAppAgentProvideruseAppAgentContext
Use this when the assistant is part of your app, not a generic widget.
@emcy/agent-sdk/react-native#
React Native binding for the same App Agent model:
useAppAgentAppAgentProvideruseAppAgentContext
Use this when you are building a native agent surface with your own screens, sheets, or docked UI.
@emcy/agent-sdk/react-embed#
Drop-in web widget:
EmcyChat
Use this when you want the fastest path to a working web embed.
Choose the right path#
Use react-embed when:#
- you want a working widget quickly
- you are embedding into a web app
- you do not need a deeply custom layout
- you want Emcy to own more of the UI surface
Use react or react-native when:#
- the assistant is a core product surface
- you need branded UI
- you want transcript, systems, approvals, or requests woven into app chrome
- you want your own client tools and workspace context
Use the low-level runtime when:#
- you are building your own framework adapter
- you need direct runtime orchestration
- you explicitly do not want the App Agent model
The minimum config#
Every integration starts with:
{
apiKey: "emcy_sk_xxxx",
agentId: "ag_xxxxx",
}For embedded same-user experiences, also pass:
{
appSessionKey: session.id,
userIdentity: {
subject: session.user.id,
email: session.user.email,
organizationId: session.organizationId,
displayName: session.user.name,
},
}That is what scopes persisted MCP auth and resumed conversations to the current signed-in host session.
A quick custom-ui example#
import { useAppAgent } from "@emcy/agent-sdk/react";
export function SupportAssistant() {
const agent = useAppAgent({
apiKey: process.env.NEXT_PUBLIC_EMCY_API_KEY!,
agentId: process.env.NEXT_PUBLIC_SUPPORT_AGENT_ID!,
appSessionKey: session.id,
userIdentity: {
subject: session.user.id,
email: session.user.email,
organizationId: session.organizationId,
displayName: session.user.name,
},
clientTools,
appContext: {
currentSurface: "billing-settings",
hostRefreshInstruction:
"After any successful billing mutation, call refreshBillingView before you answer.",
},
feedbackSource: "support-center",
});
return (
<div>
<button onClick={() => agent.composer.send("Summarize my current billing status.")}>
Ask
</button>
<div>{agent.conversation.statusLabel}</div>
</div>
);
}What useAppAgent gives you#
agent.conversation#
The conversation surface includes:
idmessagesconversationMessagestoolMessagesvisibleMessagesrenderedNodeslatestAssistantMessagelatestToolMessagelatestUserMessagelastTurnpendingTurninlineFeedstreamingContentstatusLabelisReadyisLoadingisThinkingloadMore()reset()
agent.composer#
send(prompt, { displayText? })cancel()
agent.connections#
itemsneedsAttentionconnect(serverUrl)disconnect(serverUrl)
agent.approvals#
pendingresolve(id, approved)
agent.requests#
pendingsubmit(id, values?)cancel(id)
agent.feedback#
isSubmittingerrorlastSubmittedAtlastFeedbacksubmit(...)
Recommended reading order#
- Embed an agent in your app
- Use the web embed widget
- Build custom React UI
- Build custom React Native UI
- Define client tools
- Handle approvals and input requests
