Skip to main content
Host tools are Swift functions your app registers with the Chappie client so the model can call them during a conversation. When the model decides a tool is relevant, Chappie invokes your handler, collects the result, and seamlessly feeds it back into the transcript — all without any extra orchestration code on your part. The two-step setup keeps the model’s declaration separate from the Swift implementation: first describe the tool in a ChappieHarness, then attach a ChappieHostTool handler to the client.

Register a host tool

Inspect tool call arguments

Every handler receives a ChappieToolCall value. Use argumentsJSON to get a parsed ChappieJSONValue? rather than decoding the raw JSON string yourself.
String?
The response-level output item ID assigned by the backend. May be nil for some transport paths.
String
The unique call identifier used to correlate the result with the request. Always present.
String
The tool name as declared in the harness — used by the registry to route to your handler.
String
The raw JSON string the model produced for this call’s input arguments.
ChappieJSONValue?
A convenience computed property that parses arguments into a ChappieJSONValue tree. Returns nil if the string is not valid JSON.
Return your result as a ChappieToolResult. Because ChappieToolResult conforms to ExpressibleByStringLiteral, you can return a plain string literal from your handler when you don’t need the output: label:

ChappieJSONValue — schema building and argument parsing

ChappieJSONValue is the enum used both for defining input schemas and for parsing the arguments the model sends back. Its cases map one-to-one with JSON primitives: Use nested .object and .array values to express any JSON Schema structure your tool requires. ChappieJSONValue is Codable, so you can also decode model-produced arguments directly.

Tool approval policies

By default Chappie runs tools automatically. Use ChappieToolPolicy to require user approval or block a tool entirely.
static property
Runs the tool without prompting. This is the default when you omit the policy parameter.
static factory
Emits an .approvalRequested stream event and calls your toolApprovalHandler before running the tool. Provide at least one ChappieToolPermissionScope to describe what the tool accesses.
static factory
Blocks the tool unconditionally. The handler is never called; the stream receives a .toolCallCompleted event with status == .denied.

Permission scopes

Pass one or more ChappieToolPermissionScope values to .ask or .deny so your approval UI can present a meaningful description of what the tool needs:

Requiring approval before a destructive action

Providing an approval handler

When any tool uses .ask, supply a toolApprovalHandler closure on the client. Chappie calls it with a ChappieApprovalRequest describing the pending call — display your confirmation UI there, then return a ChappieApprovalDecision:
If a tool’s policy is .ask but you don’t provide a toolApprovalHandler, Chappie denies the tool call automatically and throws ChappieClientError.toolApprovalDenied. Always pair .ask policies with a handler.

Observing tool execution with stream events

When you use client.stream(_:) or client.streamHandle(_:), Chappie emits stream events at each stage of tool execution so your UI can show real-time feedback:

Tool call round limit

Chappie allows up to 6 tool-call rounds per send, stream, or response call. If the model requests more consecutive rounds than that limit, the client throws ChappieClientError.toolLoopLimitExceeded. Design your tools to return complete, actionable results so the model can reach a final answer within a few rounds.
Returning structured JSON from your handler (rather than plain prose) lets the model extract individual fields reliably and reduces the number of follow-up tool calls needed.