Tool Invocation Helper
The tools helper lets a script invoke any published tool in its company by id — the same tools your agents call, executed through the same config, permission, and variable-substitution pipeline. It turns a script into an orchestrator: fetch with one tool, decide in code, write with another.
tools.invokeById
- Name
tools.invokeById- Type
- (toolId: string, variablesJson?: string) => string
- Description
Invokes the tool with the given id and returns its result as a JSON string.
toolIdis the tool's ID string ("V1StGXR8Z5").variablesJsonis an optional JSON object string supplying values for the tool's declared@@{name}placeholders; passnullor omit it for none.
There is deliberately no invoke-by-type: scripts reference concrete, published tools that users can see, edit, and revoke in the tool builder — never anonymous tool types. See Tools for how tools are published.
How variables merge into the tool
The invoked tool's stored config is the source of truth — you never override its shape, you only fill in the @@{name} placeholders it declares:
- Strings, numbers, booleans become string substitutions for matching
@@{name}placeholders anywhere in the config.nullsubstitutes an empty string. - Objects and arrays can't survive string substitution into typed config fields, so they are spliced in raw — but only where a config field's value is exactly
"@@{name}". A placeholder embedded inside a longer string only accepts scalar values. - The enclosing script's own variables (including platform context like
AUTESSA_COMPANY_IDand private variables) are inherited by the invoked tool automatically — you don't forward them yourself.
// Tool V1StGXR8Z5 is an AutessaDB update tool whose config contains
// "values": "@@{values}" and "rowId": "@@{rowId}"
const result = tools.invokeById("V1StGXR8Z5", JSON.stringify({
rowId: 99, // scalar -> string substitution
values: { summary: { textValue: "hello" } } // object -> spliced raw
}));
Access rules
- Same company only. The tool must belong to the company the script runs in; anything else returns
CROSS_COMPANY. - Permissions apply. Tools private to another user, without an explicit grant, are refused — the invocation goes through the same permission pipeline as agent and API calls.
Return envelope
On success you get the invoked tool's result as a JSON string, unwrapped so a single JSON.parse works regardless of how the executor produced it:
- A structured result (object/array) arrives as that JSON document.
- A result that was already a JSON string arrives verbatim — no double-encoding, one
JSON.parseis enough. - A plain-text or numeric result arrives as a valid JSON literal (e.g.
"done"or123), soJSON.parsenever fails.
On failure you get an error envelope instead:
{ "error": true, "errorCode": "TOOL_NOT_FOUND", "errorMessage": "No tool with id V1StGXR8Z5" }
Always check for error before using the result:
const parsed = JSON.parse(tools.invokeById("V1StGXR8Z5"));
if (parsed && parsed.error) {
console.error("tool failed:", parsed.errorCode, parsed.errorMessage);
}
Error codes
- Name
BAD_TOOL_ID- Type
- errorCode
- Description
toolIdcouldn't be resolved — null, empty, not a valid tool ID, or an unsupported type.
- Name
NO_SPRING_CONTEXT- Type
- errorCode
- Description
The platform application context wasn't available yet; retry later.
- Name
TOOL_NOT_FOUND- Type
- errorCode
- Description
No tool exists with that id.
- Name
MISSING_COMPANY_ID- Type
- errorCode
- Description
The script has no company id in context (e.g. a computed column) — company-scoped dispatch is refused.
- Name
BAD_COMPANY_ID- Type
- errorCode
- Description
The company id in context wasn't a valid number.
- Name
CROSS_COMPANY- Type
- errorCode
- Description
The tool belongs to a different company.
- Name
BAD_TOOL_CONFIG- Type
- errorCode
- Description
The tool exists but its stored config is unreadable or has no tool type.
- Name
INVALID_CONFIG- Type
- errorCode
- Description
Building the executable config failed — usually a missing or wrongly-typed variable for a required placeholder.
- Name
NULL_RESULT- Type
- errorCode
- Description
The executor ran but produced no result.
- Name
EXECUTION_ERROR- Type
- errorCode
- Description
The tool executed and failed;
errorMessagecarries the underlying cause.
Composition pattern: script as orchestrator
The canonical use is read → decide → write, with each side effect going through a published, user-visible tool:
// 1. Read: a query tool returns matching rows.
const rows = JSON.parse(tools.invokeById("kA9mB2xQ7p", JSON.stringify({
status: "overdue"
})));
if (rows.error) {
response.setResponse(JSON.stringify({ error: rows.errorMessage }));
} else {
// 2. Decide: pure JavaScript in between.
const toEscalate = rows.filter(r => parseInt(r.daysOverdue) > 30);
console.log("escalating", toEscalate.length, "of", rows.length, "rows");
// 3. Write: an update tool per row.
const failures = [];
for (const row of toEscalate) {
const res = JSON.parse(tools.invokeById("pQ4rT8nW2c", JSON.stringify({
rowId: row.id,
values: { priority: { textValue: "high" } }
})));
if (res && res.error) failures.push({ rowId: row.id, error: res.errorCode });
}
response.setResponse(JSON.stringify({
escalated: toEscalate.length - failures.length,
failures: failures
}));
}
Each invokeById call is synchronous and runs the full tool pipeline. Loops over many rows work, but budget accordingly — prefer a tool that operates on batches when one exists.
Related
- Tools
- Global bindings — how
@@{name}placeholders map tovariables - Examples
- AutessaScript overview