Your app hands a run its own tools. The model calls them on the user's machine, the call comes back to your app, and your code executes it.
Your tools are your code. Soba never sees the implementation, only the name, the
description and the input schema, enough for a model to decide to call it.
Attach them to the run:
JavaScript
const run = await soba.run({
user: session.user.id,
prompt: "How many open invoices does Acme have?",
tools: [
{
name: "lookup_invoices",
description: "Find invoices for a customer.",
inputSchema: {
type: "object",
properties: { customer: { type: "string" } },
required: ["customer"],
},
execute: async ({ customer }) => db.invoices.openFor(customer),
},
],
});
The model calls it wherever the run is executing, the call arrives back on your run's
stream, and your execute answers it:
JSON
{"type":"tool_call","runId":"r_01","callId":"c_1","name":"lookup_invoices","input":{"customer":"Acme"}}
Over raw HTTP that is a frame on the stream and a POST back the other way, to
/v1/runs/:id/tool_result. The
SDK turns both into the one execute function above.
isError: true on a result marks a failure the model should see and can react to,
rather than one that kills the run.
Nothing about your tools moves to Soba. They run where they already run, against the
data they already touch: your database, your session, your permissions.
The machine can refuse#
JSON
{ "allowAppTools": false }
A machine owner can decline to be a tool-calling engine at all. Its runtimes then
report that they do not support tools, and no tools you send will be honoured.
Which runtimes can do it#
A machine reports per runtime whether it can execute tool schemas your app supplies.
Check that before sending tools rather than assuming, because an agent runtime that
cannot accept external tool schemas will otherwise silently ignore them.
The gate still applies#
App-defined tools are subject to the same resolution as built-in ones. A tool your app
defines does not bypass the policy intersection, and a tool that
lands in the machine's askable set still needs a live approval.