This guide puts a text agent inside your own React app: a chat panel for signed-in users with streamed replies, photo attachments, and a tool that reads your app’s data. Your server starts each chat and mints a one-hour chat token; the browser talks to that one chat with TalqingChat from @talqing/client. You build the UI. You need: an LLM provider key, a personal access token with the EDITOR role on your server, and a stable id for each signed-in user. Text has no per-minute fee; see pricing.

1. Create and publish the text agent

A chat can only start on a published agent.
Pick any llm your key covers from GET /v1/catalog. To let a returning user’s next chat remember earlier ones, set conversation.context — see conversation memory.

2. Start the chat and mint a token on your server

A personal access token can read, change and delete everything in the workspace. It must never reach the browser. The browser gets a chat token, which opens one chat for one hour and nothing else.
app/api/chat/token/route.ts
  • contact_key identifies the person across chats. Derive it from your session, never from browser input. The prefixes phone:, telegram:, whatsapp:, sip: and stream: are reserved.
  • userdata is what the agent knows about them — {{userdata.name}} in the prompt and tools. Because your server writes it, identity comes from your session, not from what the user types. See userdata.
  • One open chat per contact and agent. POST /v1/chats ends the existing open one, so look it up first. That also makes this endpoint safe to call on every page load and token refresh.

3. Render the chat

components/Chat.tsx
TalqingChat refetches the token shortly before it expires. What a turn returns: A chat token never sees tool calls, handoff rows, cost, analysis or userdata. Your server’s token and the dashboard see the full record. Full reference: text conversations and React and client SDK.

4. Decide what ends a chat

An open chat is not analysed and does not send session.completed. Left alone, it ends 24 hours after the user’s last message (inactivity_timeout). To end it sooner:
  • The agent, with an end_call tool, when the conversation is over.
  • The user, with a “New chat” button that calls chat.end().
  • Your server, on a schedule: GET /v1/chats?status=open, then POST /v1/chats/{chat_id}/end for chats older than you want to keep.
Ending runs the agent’s on_exit hook and post-chat analysis, and sends session.completed.

5. Accept files

Send the files and the caption as one message. talqingFileDataUrl encodes a File (downscaling a photo first) and throws a user-facing message when the file is refused.
Limits: 4 files per message, 20 MB each, any type. The agent reads photos (on a model with vision: true), PDFs and Word files; anything else is stored for you and the agent is told it cannot open it. See vision and images.

6. Give the agent a tool that reads your data

Key the lookup on account_id from userdata, which your server set, so the model cannot ask about another account.
get_account_summary.json
Create the NORTHWIND_INTERNAL_TOKEN secret first. Saving the tool warns that {{userdata.account_id}} is read but never written by a tool; that is expected, because your token route sets it. Then attach the tool with PATCH /v1/agents/{agent_id} — {"config": {"tools": [{"tool_id": "…"}]}}, including any tools already attached, since the list is replaced whole — and publish the agent again. See versions.

7. Escalate to a person

Text has no transfer to a human: the transfer operation works only on phone calls. A person at your business can still answer inside an open chat by posting agent_text, sent as the agent’s message. Escalation is a routing decision your server owns — the agent files a ticket, and your app stops minting tokens for that user and routes them to your support desk.
The response goes back to the model, so it can tell the user the ticket number your endpoint returns. When your desk takes over, end the chat with POST /v1/chats/{chat_id}/end.

Test it

  1. Use Test chat on the agent’s page in the dashboard before wiring anything.
  2. Send from your page and watch events: assistant.started, deltas, assistant.completed, turn.result.
  3. Reload mid-chat. The same transcript should repaint; an empty panel means your token route started a new chat instead of reusing the open one.
  4. Sign in as a second user. Each should see only their own history.
  5. Ask something only the tool knows, then confirm the function_call item in GET /v1/chats/{chat_id}/items with your workspace token.
  6. End the chat. GET /v1/chats/{chat_id} shows status: "ended", then analysis a few seconds later.
Read real conversations under Monitor → Conversations in the dashboard; see conversations.

Limits of this setup

  • Every chat needs your server to start it and mint its token; there is no public agent id a browser can use.
  • No typing indicator or read receipts are reported on web; the “Thinking…” state is inferred from the request in flight.
  • Each turn re-sends the whole chat to the model, so long threads grow input-token cost on your key.

Next

Text conversations

Chats, streaming, items and browser tokens in full.

React and client SDK

Every export of @talqing/client and @talqing/react.