doo.ai
doo.ai lets a script ask a Tabidoo AI agent a question and use the answer like any other value β summarize a long note, classify an incoming request, translate a text, extract data from a document, draft a reply. You write the prompt, the agent answers, your script decides what to do with the answer.
It is the same agent technology the AI assistant in the application uses; doo.ai is the way to reach it from your own scripts.
Where you can use it
Place | Works |
|---|---|
Workflow β Run Script step (server) | yes |
Button field, Free HTML field, form scripts (browser) | yes |
Calculated field | no β a calculated field is a single synchronous expression, is asynchronous |
Always await the call:
const res = await doo.ai.callAgent('Summarize the text in three sentences.');
callAgent
The short form
Pass a string and you get the answer from the default agent:
const res = await doo.ai.callAgent(`Classify this request as Complaint, Question or Order:\n${doo.model.text?.value}`);
console.log(res.message);
The full form
Pass an object when you need more control:
const res = await doo.ai.callAgent({
prompt: `Summarize the following note in two sentences:\n${doo.model.note?.value}`,
context: 'You write in Czech, in a neutral business tone.',
agentShortName: 'my-agent',
useWebSearchTool: false
});
Property | Meaning |
|---|---|
| The question or instruction. Required. |
| Extra instructions for the agent β role, tone, output format. |
| Code of the LLM model to use. Leave out to use the agent's own model. |
| Short name of the agent to call (from the AI Agents table). |
| Id of the agent record β an alternative to . |
| The application the agent is defined in, when it is not the current one. |
| Allows Tabidoo's built-in agents to be used. |
| The agent may search the Tabidoo documentation. |
| The agent may read the structure of the application (tables, fields). |
| The agent may read the TypeScript definitions of the application. |
| The agent may search the web. |
| Files for the agent: , in base64. |
| The conversation so far β see Asking follow-up questions below. |
Every tool you switch on makes the call larger and more expensive, so switch on only what the prompt really needs.
What you get back
{
message, // the agent's answer as text
inputTokens, // tokens sent to the model
outputTokens, // tokens the model produced
credits, // the cost of this call, counted against your AI limit
chatState, // the conversation, to pass into the next call
fullAgentResult,// the raw result of the run
debugLogs // which tools the agent loaded and used
}
Examples
Write the answer into a record
const res = await doo.ai.callAgent({
prompt: `Summarize this customer note in one sentence:\n${doo.model.note?.value}`
});
if (!res?.message) {
doo.workflow.stop();
}
await doo.table.updateFields('tickets', doo.model.id, { summary: res.message });
Ask for a result you can process
The answer is plain text, so ask for the shape you want and check it before you use it:
const res = await doo.ai.callAgent({
prompt: `Return only JSON in the form {"category":"...","priority":1-5} for this request:\n${doo.model.text?.value}`
});
let data = null;
try {
data = JSON.parse(res?.message || '');
} catch (e) {
console.log('The agent did not return valid JSON: ' + res?.message);
}
Asking follow-up questions
chatState carries the conversation. Send back what the previous call returned and the agent remembers what was said:
const first = await doo.ai.callAgent('List the three main risks of this project.');
const second = await doo.ai.callAgent({
prompt: 'Now write one mitigation measure for each of them.',
chatState: first.chatState
});
Store chatState in a field (as text) when the conversation should continue in a later run.
Sending a file to the agent
const file = doo.model.attachment?.value?.[0];
const f = await doo.table.getFileBase64('tickets', file.fileId);
const res = await doo.ai.callAgent({
prompt: 'Read the invoice and return the invoice number and the total amount.',
attachments: [{ fileName: f.fileName, fileData: f.content, mimetype: f.mimeType }]
});
Your script as a tool of an agent
The other direction is possible as well: a script can be a tool that an agent calls (AI Tools, tool type Simple Script). Inside such a script:
doo.ai.aiToolParamholds the parameters the agent passed in,doo.ai.writeToAiToolResult(value)returns the result to the agent.
const id = doo.ai.aiToolParam?.orderNumber;
const rows = (await doo.table.getData('orders', { filter: `number(eq)${id}`, limit: 1 })).data;
doo.ai.writeToAiToolResult(rows[0]?.fields ?? 'Order not found.');
Cost and limits
Every call is paid for in AI tokens. The credits value of the response is what is counted against the AI token limit of your plan. In a browser script you can read the current consumption with doo.environment.getCurrentUserTechnicalLimits() β item aiTokensCount, with the limit of your plan next to it.
Even a short prompt is not cheap. An agent carries its instructions and its tools into every call, so a one-word answer can still mean thousands of input tokens. In a measured example a single trivial call cost roughly 14,000 input tokens. The more tools an agent has switched on, the higher the number.
A workflow run is stopped after 90 seconds. One AI call takes seconds, so plan for one or two per run. Never call the agent in a loop over hundreds of records β process them in batches or in one prompt.
The answer is not deterministic. The same prompt can return a differently worded answer next time. Anything you write into a field or compare against should be checked in the script first.
Troubleshooting
message comes back empty. The call did not fail and no exception was raised β check that agentShortName, agentIdand agentApplicationId point to an agent that really exists and that you have access to. Always test res?.messagebefore you use it.
The answer is in the wrong language or format. Put the requirement in context ("Answer in Czech, return only the number"), not only in the prompt.
Nothing happens in the workflow. Open the run log of the workflow. An AI call that was not written with await ends as an unhandled rejection, and the rest of the step runs without an answer.
Too many requests / the AI limit is reached. aiTokensCount is a limit of your plan, not a bug. Reduce the number of calls, shorten the prompts, or switch off the tools the agent does not need.
Related
- doo.environment β
getCurrentUserTechnicalLimits()for the current AI consumption - Getting Started with Workflow Automation
- Scripting β Getting Started