Skip to main content

Let a customer navigate your app through chat

Section ID: Guide/j8fgpgk84t#build-an-agent-that-uses-your-tools

Let a user ask the assistant to open their profile in your app. Define a navigation tool, receive the requested action, check and execute it in your app, then return the actual result so the assistant can finish its reply. The optional connected-app step extends the workflow to a supported third-party account such as Google Calendar.

Client-side tools do not go through the approval queue. Approval is a separate mechanism for tools the platform runs but a human must authorise — see approval patterns. Your application must check the user's permissions, validate the arguments and obtain any required confirmation before running its own tool; the run waits for your result.

Start with one allowed route and one tool. The completed recipe opens the customer's profile, returns the actual navigation result and displays the assistant's reply for that run. Connected SaaS tools are a separate extension after the client-tool loop works.

Prerequisites​

Section ID: Guide/j8fgpgk84t#prerequisites

  • A secret key (sk_…) for your tenant, issued through your enabled management surface or account administrator. Backend calls use the secret key plus X-On-Behalf-Of to act on behalf of a specific user. See Authentication & API Keys.

  • A conversation thread. Create one with create-thread if you do not have one. See Build an AI chat assistant for the full setup.

Step 1: Describe the navigation your app can perform​

Section ID: Guide/j8fgpgk84t#step-1-define-a-client-side-tool

Client-side tools are actions that run in your app or backend, not on the platform. Declare them in clientTools when creating the thread — or per turn via overrideGenerationConfig:

Request example: Create a new conversation thread. Example identifiers and values are illustrative; substitute authorized values.

Example request headers: X-API-Key: sk_your_key_here; X-On-Behalf-Of: user_123; Content-Type: application/json. Replace the credential and user placeholders with your own authorized values.

Response:

Response example: Create a new conversation thread. Example identifiers and values are illustrative; substitute authorized values.

Save the threadId — you'll pass it as conversationKey in every subsequent request.

Implement the corresponding action in your application before sending the test question. For this recipe, /profile must be an allowed route for the signed-in user. Declaring the tool schema does not implement navigation or validate arguments.

Step 2: Ask to open the profile and retain the pending call​

Section ID: Guide/j8fgpgk84t#step-2-send-a-message-and-receive-the-call

Send a message that makes the model want to navigate. The model reads your tool description and decides whether to call it.

Use send-message-sync for a bounded wait that can return the pending call directly. If the wait ends first or the connection drops, use the recovery flow below; do not resend the message.

Request example: Send a message and wait for the result. Example identifiers and values are illustrative; substitute authorized values.

Example request headers: X-API-Key: sk_your_key_here; X-On-Behalf-Of: user_123; Content-Type: application/json. Replace the credential and user placeholders with your own authorized values.

Response:

Response example: Send a message and wait for the result. Example identifiers and values are illustrative; substitute authorized values.

AGENT_STATUS_AWAITING_CLIENT_TOOLS means the run is paused on you. Take the id and name off the pending call, and keep clientToolCursor — you need all three in the next step.

Step 3: Navigate once and report what happened​

Section ID: Guide/j8fgpgk84t#step-3-return-the-result-and-get-the-reply

For navigate_to, check that screen names an allowed route and that the current user may open it. Run the action, then post its actual result with submit-client-tool-results-sync. The response may contain the assistant reply, another tool batch or a still-active outcome; inspect status before treating the turn as finished.

Request example: Submit client-side tool results and wait for the next segment. Example identifiers and values are illustrative; substitute authorized values.

Example request headers: X-API-Key: sk_your_key_here; X-On-Behalf-Of: user_123; Content-Type: application/json. Replace the credential and user placeholders with your own authorized values.

Response:

Response example: Submit client-side tool results and wait for the next segment. Example identifiers and values are illustrative; substitute authorized values.

After submitting the real result, handle another pending batch if one is returned; otherwise inspect the correlated run outcome. Follow the result contract before declaring the customer’s navigation complete.

Copy the pending call’s id and name into toolCallId and toolName, and return the actual resultJson. Echo the latest clientToolCursor for each synchronous batch. Another AGENT_STATUS_AWAITING_CLIENT_TOOLS response starts another batch; provisional text or a request whose wait ended early is not a terminal outcome.

Check the customer’s completed navigation​

Section ID: Guide/j8fgpgk84t#run-it

After the request above, verify the whole customer journey:

  1. The app received the complete navigate_to call, ID and current clientToolCursor.

  2. It validated /profile and the user's access before executing the action.

  3. The profile screen actually opened, and the submitted result describes that outcome.

  4. The same run reached a recognized terminal outcome, or another tool batch was handled with its new cursor.

Finished result: the screen is open and the assistant's available reply is tied to the completed action. If navigation failed, submit a truthful failure outcome rather than claiming it opened. The default five-minute answer window ends the wait on expiry; it does not establish whether an external action happened. Recover the original call before repeating an uncertain action.

Recover the call when your connection cannot stay open​

Section ID: Guide/j8fgpgk84t#if-you-cant-hold-a-connection

A worker can send with send-message and learn about a call from the enabled llm.tool_call_started delivery surface or by polling pending client tools. The event’s presence in the API does not establish that webhook delivery is enabled in your deployment.

Retain the original conversation and call IDs. Read the pending call, its deadline and current status before executing; when the call ID is known, use the exact call readback; a dropped connection does not authorize repeating an action that may already have completed. Validate arguments and permissions, reconcile the external result, then answer the same pending call with submit-client-tool-results. Inspect the resumed run to its outcome.

Do not resend the original user message to recover a lost response. That creates another send and can invoke the configured cancel, queue, reject or ignore policy. If the call has become terminal or its deadline has passed, stop the old execution attempt and use the reported outcome.

Separate recipe: let the customer connect a calendar​

Section ID: Guide/j8fgpgk84t#step-4-connect-a-third-party-app-optional

Use a connected calendar when the assistant needs a supported external account. The hosted Pipedream integration must be enabled for your deployment; it exposes connected accounts through pipedream:{appSlug} MCP servers without your application storing their credentials.

  1. Follow the connected-account recipe to issue a fresh Connect link for this attempt and use its returned expiry when the user chooses to connect. Redirect them through the authorized flow.

  2. After the return, list accounts to confirm the intended calendar exists; a redirect alone is not the result.

  3. Select pipedream:google_calendar for the conversation and inspect its discovered tools. Discovery occurs per turn, so a later connection is picked up on the next message.

  4. Ask for work supported by those tools, apply the required platform approval policy, and follow the run to its actual calendar outcome.

Finished result: the chosen calendar is connected and the requested calendar work has a known outcome. A connection or tool list alone does not establish that the work finished. Use connected-app recovery for an unhealthy account and tool recovery for a lost call response.

Diagnose a platform MCP tool independently​

Section ID: Guide/j8fgpgk84t#try-it-out

If the connected-app variant fails before a useful tool result, test an authorized platform tool directly using the exact discovered server, name and argument schema. That diagnostic bypasses the conversation; it cannot test the navigate_to action implemented in your app.

Keep direct memory-tool experiments to isolated or operator-qualified data. A caller-supplied memory user ID needs trusted-backend authorization; the authentication header does not automatically rewrite that argument. See memory scope before using real records.

Next steps​

Section ID: Guide/j8fgpgk84t#next-steps

I want to...Go to
Understand all tool sources and how they interactAgent tools
Connect users' third-party SaaS accountsConnected apps
Discover what MCP servers and tools are availableList available servers
Configure approval policies for platform toolsAgent tools — approval flow
Browse all LLM API endpointsLLM API Reference

Document ID: Guide/j8fgpgk84t