Hooks

Hooks

Hooks read the call and act on it, imported from curb. Use useState and useEffect from react, as in any React project.

HookWhat it gives you
useRouterLoad a skill from code
useRoutePathThe current skill’s path
useAgentInfoEverything the call knows
useClientWhat the caller’s page said
useSessionThe active providers, and this call’s identity
useVariantThis call’s variant of an experiment
useSendSend a message to the page or the host
useMessageHandle a message from the page or the host
useTransferCallPut the caller through to a number

A hook made by createAgentStore holds state that lasts the whole call.

useRouter

const { push } = useRouter();

push(path) loads a skill and makes it active, from code. Use it when a tool’s result decides what comes next (Complex handoffs).

useRoutePath

const path = useRoutePath();

The active skill’s path, or "" before the model has read a skill.

useAgentInfo

const info = useAgentInfo();
const number = useAgentInfo((info) => info["caller.phoneNumber"]);

All the call’s info, or one value with a selector. Which keys exist is in How a call opens. The agent re-renders when a selected value changes.

useClient

const client = useClient();

What the caller’s page said, the client.* values without the prefix. Anyone can edit a link, so it is never proof of identity (Knowing the caller).

useSession

const { settings, call } = useSession();
ValueWhat it is
settingsThe effective providers
call.sessionIdThe host’s id for this call. On a LiveKit worker, the room name; in curb dev, the preview conversation’s id
call.scratchDirA writable directory of this call’s own, removed when the call ends. Not set in curb dev

call is set on every route. Read a call’s identity here, never from process.env: a runner that serves several calls has one environment for all of them.

useVariant

const greeting = useVariant("greeting");

This call’s variant of an experiment, or undefined where no variants are assigned (Goals and experiments).

useSend

const send = useSend();
MethodWhat it does
toClient(key, payload?)Sends to the caller’s page. A phone call has no page, so it is dropped with a warning
toHost(key, payload?)Sends to the host. With no host, it is dropped with a warning
askHost(key, payload?, { timeoutMs? })Sends to the host and resolves with its reply’s payload. Rejects with HostUnavailableError, or HostTimeoutError after timeoutMs (10000)

See App messages.

useMessage

useMessage("cart.updated", {
  from: "client",
  schema: z.object({ total: z.number() }),
  onMessage: ({ total }) => setTotal(total),
});

Handles every message with that key for as long as the component is mounted.

OptionTypeWhat it does
from"client" or "host"Who may send it
schemaZod schemaA payload it refuses is answered invalid_payload and never reaches onMessage
onMessage(payload, meta) => unknownWhat it returns is the reply to a client’s ask

useTransferCall

const transfer = useTransferCall();
const { outcome, code, message, transferId } = await transfer({ to: "+493012345678" });
OptionTypeDefaultWhat it does
tostringThe number in international format
ringTimeoutSecondsnumber30How long it rings, 10 to 60 seconds
announcestringnoneSaid to the caller before it dials

outcome is answered, no_answer, busy, failed or refused. It never rejects for an outcome, and throws TypeError for a bad request. See Human handoff.

Next steps