AI Orchestrator Deep Dive — Building Tool-Calling Agents Inside Workflows
Most workflow nodes are predictable: a data fetcher returns data, an indicator returns a series, a notifier sends a message. The AI Orchestrator is different. It is an autonomous agent that receives a task, decides which of your workers to call, chooses their parameters, observes the results, and keeps going until it can write an answer.
That makes it the most flexible node in ApudFlow — and the one that benefits most from a clear mental model.
This article explains how the orchestrator works under the hood, how to configure it safely, and which patterns work well for financial-market automation.
The mental model
A traditional workflow is a pipeline. You decide the order of operations while designing it:
[Fetch prices] -> [Fetch news] -> [Indicator] -> [Summarise] -> [Telegram]
The AI Orchestrator turns that pipeline into a delegation. You describe the outcome and the available tools; the agent decides the route:
[Trigger] -> [AI Orchestrator] -> [Telegram / Condition / Save to DB]
|
+-- may call: fetch_price
+-- may call: fetch_news
+-- may call: browse_calendar
+-- may retry a worker with different parameters
The orchestrator does not replace your workers. It is a coordinator. Each tool call is a real worker execution, with the same parameters, credentials, and side effects as if you had placed that worker directly in the workflow.
Use it when the task needs reasoning across sources, adaptation after seeing intermediate data, or a written analysis. Use ordinary workers when the steps are fixed and known in advance.
How the agent loop works
The orchestrator is a ReAct-style tool-calling agent. A run looks like this:
- Load context. The node receives your
prompt, the selectedallowedWorkers, workflow variables, the current time, and — when workflow memory is enabled — previous sessions and saved facts. - Expose tools. Each allowed worker becomes a tool with a JSON schema
generated from its
parameters_schema. The model sees the worker name, description, and parameter contract. - Reason and act. The model decides whether it has enough information. If not, it calls a tool. The result is appended to the conversation as an observation.
- Adapt. If a result is empty, malformed, or does not answer the question, the agent can retry with different parameters or choose another worker.
- Finish. When the model writes a final response, the node extracts the answer, optional score, trace, and usage statistics.
The loop is bounded by guardrails: maxSteps, maxRuntimeSeconds,
toolTimeout, tokenBudget, and maxToolCalls. The agent cannot loop forever
or spend without limit.
What the model actually sees
For every allowed worker, the orchestrator builds a compact tool description from the worker definition:
- worker name and type,
- description,
- parameter names, types, required flags, defaults, and descriptions.
The model does not receive every worker in your library. It only sees the workers you selected. This is the most important design decision for quality and cost: a focused tool set produces better decisions than a catalogue of hundreds of nodes.
Tool calls are real worker calls
When the agent calls fetch_price, the orchestrator executes the same worker
logic that a normal fetch_price node would execute. That means:
- API keys and provider settings are used as usual,
- rate limits and credits apply,
- side effects such as sending a Telegram message or writing to a database happen for real,
- the call appears in the
callstrace with its parameters and a result preview.
Because of this, you should treat allowedWorkers as a permission list, not just
a suggestion.
Configuring the node
The generated worker documentation contains the full parameter table. The core configuration is intentionally small:
| Parameter | Purpose |
|---|---|
prompt | The task, expected output, and constraints. |
allowedWorkers | The only workers the agent may call. |
memoryScope | run, workflow, or none. |
advancedSettings | Reveals planning and guardrail options. |
The prompt
The prompt is the contract between you and the agent. A good prompt states:
- Goal — what decision or artefact you need.
- Sources — which kinds of data matter, and any date range or timezone.
- Output format — bullet list, table, Telegram message, JSON, maximum length.
- Fallback — what to do when a source is empty or unavailable.
- Scoring — whether the answer should end with
SCORE: nfor a Condition node.
Example:
Prepare a concise EURUSD market brief for the London session.
Use the last 24 hours of price action, the most relevant news, and the
high-impact events in the next 48 hours. Compare the technical picture with
the news flow and call out disagreements.
Return:
1. Three bullet points of evidence.
2. A directional bias: bullish, bearish, or neutral.
3. A confidence score from 1 to 5 on a final line exactly like: SCORE: 4
If news is unavailable, say so explicitly and continue with price and calendar
data. Do not invent headlines.
Choosing allowed workers
The worker picker hides nodes that cannot be executed as tools:
- trigger nodes — Schedule, Webhook, List Change, User List, and similar,
- visualization/widget nodes — Table, Chart, Metric, Markdown,
- the orchestrator itself and
parameter_loop.
Everything else that performs work can be exposed: data connectors, processing workers, indicators, AI workers, HTTP/Python/SQL tools, and flow workers.
A practical selection for a market brief:
fetch_price
fetch_news
browse_calendar
A practical selection for a research task:
fetch_price
fetch_news
fetch_economic_calendar
python_exec
ai_summarizer
Keep the list between 5 and 10 workers. More tools increase prompt size, latency, cost, and the chance of a wrong selection. If a task needs 20 sources, consider splitting it into two orchestrator nodes or using a fixed pipeline for the deterministic parts.
Memory scope
memoryScope controls persistence:
| Scope | Behaviour |
|---|---|
run | Memory exists only for the current run. Nothing is saved. |
workflow | Session history and long-term facts persist for this workflow/node/owner. |
none | No memory is loaded or saved. |
With workflow scope, the agent gets two additional tools:
remember— save a stable fact, preference, data-source lesson, or convention.recall— search saved facts before making assumptions.
Memory is keyed by workflowId + nodeId + ownerId and stored in MongoDB:
orchestrator_memories— recent session history,orchestrator_memory— durable facts.
Store knowledge that will still be true next week:
- "The CoinGlass funding-rate endpoint is the preferred source for BTC derivatives in this workflow."
- "Report prices in EUR and use the Europe/London timezone."
- "When the calendar worker returns an empty list, retry with a 7-day window."
Do not store transient snapshots:
- "BTC is 86,500 right now."
- "The RSI is 61.4."
Those belong in the run output, not in long-term memory.
Planning and guardrails
Open advancedSettings when you need to tune behaviour:
| Setting | Default | What it controls |
|---|---|---|
planningMode | react | plan writes a numbered plan before acting. |
maxSteps | 15 | Maximum reasoning/tool steps. |
maxRuntimeSeconds | 180 | Wall-clock budget for the node. |
toolTimeout | 180 | Maximum time for one delegated worker. |
maxHistory | 20 | Past sessions kept for workflow memory. |
tokenBudget | 0 | Total prompt+completion tokens; 0 = unlimited. |
maxToolCalls | 0 | Hard cap on worker invocations; 0 = unlimited. |
planningMode="plan" adds a planning step. It is useful for multi-source
research where a written plan reduces wasted calls, but it adds latency and
tokens. For short briefs, react is usually enough.
maxSteps and maxRuntimeSeconds are the primary safety nets. tokenBudget
and maxToolCalls are hard stops for scheduled or high-frequency workflows
where cost predictability matters.
Identical worker calls with identical parameters are cached inside a run. A
retry that changes a parameter is a new call and counts against maxToolCalls.
Reading the output
The orchestrator returns several fields. Downstream nodes can read any of them
through the usual variable syntax, for example
vars['Orchestrator']['answer'].
| Field | Description |
|---|---|
answer | Final written response. This is the main result. |
plan | The plan produced in planning mode, or the working plan. |
calls | Trace of worker calls: worker, parameters, and result preview. |
workers_used | Unique worker types actually invoked. |
status | finished when the agent completed normally. |
steps | Number of reasoning/tool steps used. |
usage | Token accounting: prompt, completion, total, cached, and LLM calls. |
score | Numeric score extracted from a final SCORE: n line. |
error | Error message when the agent failed or produced no answer. |
In the node output panel, answer is shown as its own one-row answer group
next to the calls and workers_used tables. Open calls to see what the agent
did. This is the first place to look when the answer is surprising.
Score-based branching
The orchestrator does not decide which downstream nodes run. If you need conditional execution, ask for a score and use a Condition node.
Prompt ending:
End with a line exactly like: SCORE: 4
Condition expression:
vars['Orchestrator']['score'] >= 4
Then connect the true branch to Telegram and the false branch to a no-op or a database logger. This keeps the decision explicit and testable.
Under the hood
The implementation lives in three backend modules:
backend/agents/orchestrator_agent.py— the agent loop, prompt assembly, step limits, final-answer extraction, and score parsing.backend/agents/workflow_tools.py— converts allowed worker definitions into tool schemas and executes delegated calls.backend/agents/memory.py— session and fact persistence for workflow memory.
The node itself is backend/workers/orchestrator.py. It validates parameters,
runs the agent asynchronously, and returns the output fields described above.
This separation matters when debugging: a failed tool call is a worker issue, an empty answer is usually a model/prompt/guardrail issue, and missing memory is a scope or identity issue.
Production patterns
Pattern 1 — Market brief
Use case: a scheduled morning brief for one or more symbols.
[Schedule 07:00] -> [AI Orchestrator] -> [Telegram]
Allowed workers: fetch_price, fetch_news, browse_calendar.
Prompt focus: last 24 hours of price action, top news, next 48 hours of high-impact events, explicit bias, concise Telegram formatting.
Why it works: the agent can skip news when the feed is empty, retry the calendar with a wider window, and still produce a useful brief from price data.
Pattern 2 — Conditional alert
Use case: only notify when a setup is strong enough.
[Schedule] -> [AI Orchestrator] -> [Condition: score >= 4] -> [Telegram]
Prompt focus: analyse the setup, write a Telegram-ready alert, end with
SCORE: n; answer NO_SIGNAL when there is no setup.
Why it works: the LLM handles nuance, while the Condition node enforces a deterministic threshold. You can audit both the score and the reasoning.
Pattern 3 — Multi-source research
Use case: compare price action, news, and macro events before a trading decision.
Allowed workers: fetch_price, fetch_news, fetch_economic_calendar,
python_exec.
Prompt focus: fetch each source, identify disagreements, return a table with
claim, source, and confidence. Ask the agent to use python_exec for any
calculation rather than doing arithmetic in its head.
Why it works: the agent can chain sources and use code for calculations, while the trace shows exactly which source produced each claim.
Pattern 4 — Memory-backed analyst
Use case: a recurring analyst that remembers your preferences and past lessons.
Set memoryScope="workflow". On the first run, ask the agent to remember
stable preferences:
Remember that this workflow reports in EUR, uses the London timezone, and
prefers a maximum of 120 words for Telegram messages.
Later runs can recall those facts. Keep the prompt focused on the current
market question; the agent will retrieve the conventions it needs.
Pattern 5 — Cost-controlled scheduled run
Use case: a high-frequency workflow where cost must be predictable.
Set:
maxSteps: 8
maxRuntimeSeconds: 90
maxToolCalls: 6
tokenBudget: 20000
planningMode: react
Keep allowedWorkers to the three or four sources that actually matter. Log
usage to a database so you can monitor cost per run and alert on anomalies.
Prompt engineering checklist
- State the output contract. "Return a table with columns X, Y, Z" is better than "analyse this".
- Anchor time. Say "last 24 hours", "next 48 hours", and the timezone when relative dates matter.
- Name the decision. "Give a bullish/bearish/neutral bias" is easier to evaluate than "tell me what you think".
- Define missing-data behaviour. "If news is unavailable, say so and continue" prevents invented headlines.
- Ask for evidence. Require the agent to mention the worker or source behind each important claim.
- Use code for maths. Delegate calculations to
python_execwhen precision matters. - Keep it short. Long prompts with many competing goals produce diluted answers. Split complex tasks into multiple orchestrator nodes.
Debugging guide
| Symptom | Likely cause | What to check |
|---|---|---|
| Empty answer | Model stopped, guardrail hit, or provider error | status, error, usage, maxRuntimeSeconds |
| Agent did not call a worker | Worker not selected, or prompt did not require it | allowedWorkers, calls, prompt wording |
| Wrong worker chosen | Too many similar tools, vague prompt | Reduce the tool list, describe the source explicitly |
| Stale or missing data | Missing date range or timezone | Prompt constraints, worker parameters in calls |
| Timeout | Slow worker or too many steps | toolTimeout, maxSteps, maxRuntimeSeconds |
| Unexpected cost | Too many steps/tools, planning mode | usage, maxToolCalls, tokenBudget, maxSteps |
| Memory not persisting | Wrong scope or different node/owner | memoryScope, workflow/node identity |
| Trigger or widget missing | By design | Only executable workers are tools |
When in doubt, read the calls trace first. It tells you what the agent
actually did, which is usually more useful than guessing from the final answer.
Orchestrator vs other AI nodes
| Node | Best for |
|---|---|
| AI Orchestrator | Multi-step reasoning across several workers, adaptive tool use, written analysis. |
| AI Makler | Trading analysis with structured orders and persistent trading memory. |
| AI Classifier | A single classification decision from a prompt. |
| AI Summarizer | Condensing one input into a shorter text. |
| Run Workflow | Deterministic workflow-to-workflow orchestration without an LLM. |
A useful rule: if you can draw the exact sequence of steps before runtime, use a normal pipeline or Run Workflow. If the sequence depends on what the data says, use the AI Orchestrator.
Limitations
- The orchestrator is only as good as the tools you give it. A missing or poorly described worker cannot be used reliably.
- It is non-deterministic. The same prompt can produce different tool sequences.
- It consumes LLM tokens and real worker credits. Guardrails are not optional in production.
- It does not replace deterministic risk checks. Use Condition nodes, Python validation, and explicit thresholds for anything that can move money.
- It does not decide downstream execution. Branching belongs to Condition nodes.
Production checklist
Before scheduling an orchestrator workflow:
- The prompt states the goal, output format, time range, and fallback.
-
allowedWorkerscontains only the tools the task needs. -
maxSteps,maxRuntimeSeconds, andmaxToolCallsare set. -
tokenBudgetis set for high-frequency runs. - The
callstrace has been reviewed on a real run. - Empty-data and provider-error paths have been tested.
- Score-based branching uses a Condition node, not prompt-only logic.
-
usageis logged for cost monitoring. - Workflow memory stores stable facts, not transient prices.
Summary
The AI Orchestrator is a tool-calling agent that turns a fixed pipeline into a delegation. You provide the goal and a focused set of workers; it chooses the parameters, chains the calls, adapts to missing data, and writes the answer.
The winning formula is simple:
- Give it a small, relevant tool set.
- Write a prompt with an explicit output contract.
- Add guardrails for steps, time, tokens, and tool calls.
- Inspect the
callstrace. - Use Condition nodes for deterministic branching.
Used this way, the orchestrator is not a black box. It is an auditable reasoning layer that sits between your data workers and your notification or execution workflows.
This article is for educational purposes only and does not constitute investment advice. Financial markets involve risk. Always validate automated outputs and use appropriate risk controls.