FlowAiAgent
An AI agent node that integrates LLMs with tools and memory to execute autonomous, multi-step reasoning tasks. Choose an agent type (reasoning strategy), an LLM provider, the tools the agent can call, and optionally a persistent memory backend.
How the Reasoning Loop Works
Every agent type follows a think-act-observe cycle. Each iteration the model reads the goal, accumulated context, and tool definitions, then either calls a tool or declares the goal complete.
The loop terminates when the model produces a final answer (success) or maxIterations is exhausted (error). On success the node routes to the success port. On iteration exhaustion or LLM failure it routes to the error port.
Agent Types
Select the reasoning strategy that best matches your task. The agent type is set via the agentType config key.
tools
ReAct-style tool-calling agent. Iterates LLM function-calling calls until the model declares the task complete with no further tool calls. Default and most versatile type.
reAct
Explicit Reason + Act text loop. The LLM emits structured Thought / Action / Observation blocks that are parsed after each iteration. Provides a transparent chain-of-thought trace.
conversational
Maintains conversation history across invocations using the configured memory backend. Optimised for chat-style interactions where continuity across separate workflow runs matters.
planExecute
Two-phase agent. First generates a complete multi-step plan, then executes each plan step in sequence. Reduces hallucination risk on complex, structured tasks by committing to a plan before acting.
sql
Natural-language to SQL agent. Connects to a database, introspects the schema, generates a SQL query from the user's question, executes it, and returns formatted results. Requires sqlConnectionString.
stream
Streaming output mode. Identical to tools but emits token deltas progressively to a streamCallbackUrl in real time. Use for chat interfaces where low perceived latency matters.
When to Use
- Customer support automation: Give the agent tools to look up accounts, check order status, query FAQs, and send emails. The agent handles any combination of questions without hard-coded branching.
- Data analysis with database queries: Use the
sqlagent to answer business questions in plain English — the agent introspects the schema, writes a query, and returns formatted results. - Document Q&A: Combine with FlowRag — register the knowledge query as a tool so the agent retrieves relevant context autonomously before generating an answer.
- Multi-step workflow orchestration: Use the
planExecutetype to break complex goals into verified steps, then execute each step with appropriate tools — data enrichment, API calls, record updates. - Code review agent: Give the agent tools to read files, run linters, and post comments. The agent iterates over flagged issues until a complete review is produced.
LLM Providers
| Provider | Config Value | Notes |
|---|---|---|
| OpenAI | openai | Supports gpt-4o, gpt-4o-mini, o1. Default base URL used unless overridden. |
| Anthropic | anthropic | Supports claude-opus-4, claude-sonnet-4-6, claude-haiku-3-5. Recommended for complex reasoning. |
| Azure OpenAI | azureOpenAI | Requires llmBaseUrl pointing to the Azure deployment endpoint. |
| Google Gemini | gemini | Supports gemini-1.5-pro, gemini-1.5-flash. |
| Groq | groq | High-speed inference. Requires llmBaseUrl for the Groq API endpoint. |
| Ollama | ollama | Self-hosted models. Requires llmBaseUrl pointing to the local Ollama instance. |
Memory Backends
| Backend | Config Value | Best For |
|---|---|---|
| In-Memory | inMemory | Stateless — no persistence across workflow runs. Default. Use for single-invocation tasks. |
| Redis | redis | Fast, ephemeral cross-run memory. Set a TTL for session expiry. Requires memoryConnectionString. |
| PostgreSQL | postgres | Durable conversation history. Best when audit trail of past turns is required. Requires memoryConnectionString. |
| MongoDB | mongodb | Document-store memory. Flexible schema for complex session payloads. Requires memoryConnectionString. |
Configuration
Core Fields
| Field | Required | Description |
|---|---|---|
agentType | Required | Reasoning strategy. One of: tools, reAct, conversational, planExecute, sql, stream. Default: tools. |
llmProvider | Required | LLM provider key. One of: openai, anthropic, azureOpenAI, gemini, groq, ollama. Default: openai. |
llmCredentialId | Required | Credential ID referencing the LLM API key stored in the BizFirst Credentials Manager. The key is never stored raw in node config. |
llmModelId | Required | Model identifier, e.g. gpt-4o, claude-sonnet-4-6, gemini-1.5-pro. |
prompt | Required | The user's task description or question. Supports {{ expressions }} for runtime value injection. |
systemMessage | Optional | System-level instructions defining persona, constraints, or domain knowledge. Injected before the user prompt. |
llmBaseUrl | Optional | Override the API base URL. Required for azureOpenAI, groq, and ollama. |
temperature | Optional | Sampling temperature 0.0–2.0. Default: 0.7. Use 0.0–0.2 for data extraction and routing tasks. |
maxTokens | Optional | Maximum tokens for each LLM response. Null uses provider default. Applies per iteration, not total. |
Tool Configuration
| Field | Required | Description |
|---|---|---|
enabledTools | Optional | Comma-separated or JSON array of tool names the agent may invoke, e.g. workflow,httpRequest,calculator. If empty, the agent has no tools and produces a single-turn response. |
toolWorkflowId | Optional | ID of the BizFirst sub-workflow to invoke when the workflow tool is called. |
toolWorkflowDescription | Optional | Human-readable description of what the workflow tool does — shown to the LLM to guide its tool selection. |
toolWorkflowBaseUrl | Optional | Absolute base URL for the internal workflow trigger API when using the workflow tool. |
toolHttpRequestAllowedDomains | Optional | Comma-separated list of permitted domains for the httpRequest tool. Empty means all domains are permitted. |
maxIterations | Optional | Safety cap on tool-calling loop iterations. Range: 1–50. Default: 10. Agent fails with MAX_ITERATIONS_REACHED if exceeded. |
returnIntermediateSteps | Optional | When true, includes per-iteration snapshots (thought, tool calls, tool outputs) in the intermediateSteps output field. Default: false. |
Memory Configuration
| Field | Required | Description |
|---|---|---|
memoryBackend | Optional | Persistence backend. One of: none, inMemory, redis, postgres, mongodb. Default: none. |
sessionId | Optional | Groups memory by conversation or user session. Supports {{ expressions }} for dynamic values, e.g. {{ $input.userId }}. |
conversationId | Optional | Secondary grouping key within a session. Use to separate multiple concurrent conversations for the same user. |
memoryWindowSize | Optional | Number of past message turns to load from memory at the start of each invocation. Default: 10. |
SQL Agent Fields (agentType: sql)
| Field | Required | Description |
|---|---|---|
sqlConnectionString | Required | Database connection string. Required when agentType is sql. |
sqlProvider | Optional | Database driver. One of: postgres, sqlserver. Default: postgres. |
sqlReadOnly | Optional | When true (default), blocks all non-SELECT statements. Prevents the agent from issuing mutations. |
sqlTopK | Optional | Maximum rows to return from each SQL execution. Range: 1–1000. Default: 50. |
sqlAllowedTables | Optional | Comma-separated list of table names the agent may query. Empty means all tables. Use to restrict schema surface area. |
sqlIncludeSchema | Optional | When true (default), the table schema is included in the LLM prompt to improve query accuracy. |
Streaming Agent Fields (agentType: stream)
| Field | Required | Description |
|---|---|---|
streamCallbackUrl | Optional | HTTP endpoint to POST streaming token delta events to as they arrive from the LLM. |
streamIncludeToolEvents | Optional | When true, tool call events are included in the stream callback. Default: false. |
streamIncludeTokens | Optional | When true, the final stream event includes a token usage summary. Default: false. |
Sample Configuration JSON
{
"nodeType": "flow-ai-agent",
"agentType": "tools",
"llmProvider": "anthropic",
"llmCredentialId": "42",
"llmModelId": "claude-sonnet-4-6",
"systemMessage": "You are a helpful customer support agent for Acme Corp. Always be concise and cite specific order numbers when found.",
"prompt": "Resolve this customer inquiry: {{ $input.customerMessage }}",
"enabledTools": "lookupOrder,searchKnowledgeBase,sendEmail",
"maxIterations": 8,
"temperature": 0.2,
"returnIntermediateSteps": false,
"memoryBackend": "redis",
"sessionId": "{{ $input.customerId }}",
"memoryWindowSize": 10
}
Validation Errors
| Error | Cause |
|---|---|
llmModelId is required | llmModelId is empty or missing. |
llmCredentialId is required | llmCredentialId is empty or missing. |
prompt is required | prompt field is empty after expression evaluation. |
agentType must be one of: ... | agentType value is not a recognised agent strategy. |
maxIterations must be between 1 and 50 | maxIterations is outside the permitted range. |
temperature must be between 0.0 and 2.0 | temperature is outside the 0.0–2.0 range. |
sqlConnectionString is required for sql agent | agentType is sql but no sqlConnectionString is provided. |
sqlTopK must be between 1 and 1000 | sqlTopK is outside the permitted range. |
Output
Success Port
| Field | Type | Description |
|---|---|---|
output | string | Final answer text produced by the agent after completing all reasoning iterations. |
operation | string | Agent type that handled the execution, e.g. "tools". |
iterationsUsed | number | Number of reasoning iterations consumed. Compare against maxIterations to detect agents near the limit. |
durationMs | number | Wall-clock execution time in milliseconds for the entire agent run. |
sessionId | string | Session ID used for memory persistence, if configured. |
totalUsage.promptTokens | number | Cumulative prompt tokens consumed across all iterations. |
totalUsage.completionTokens | number | Cumulative completion tokens generated across all iterations. |
totalUsage.totalTokens | number | Total tokens consumed (prompt + completion). |
intermediateSteps | array | Per-iteration snapshots when returnIntermediateSteps is true. Each entry contains iteration number, assistant text, tool calls, tool results, usage, and duration. |
Error Port
Fires when the agent fails. Common causes: LLM API error, tool execution failure, maxIterations exceeded without a final answer.
| Field | Type | Description |
|---|---|---|
errorMessage | string | Human-readable error description. |
errorCode | string | Structured error code. Values: LLM_ERROR, TOOL_EXECUTION_ERROR, MAX_ITERATIONS_REACHED, VALIDATION_ERROR. |
operation | string | Agent type that was running when the error occurred. |
iterationsUsed | number | Iterations consumed before the error (useful for diagnosing MAX_ITERATIONS_REACHED). |
Sample Output JSON
{
"output": "The Q3 revenue was $4.2M, up 18% from Q2. Top-performing region was EMEA at $1.8M.",
"operation": "tools",
"iterationsUsed": 3,
"durationMs": 4120,
"sessionId": null,
"totalUsage": {
"promptTokens": 1200,
"completionTokens": 340,
"totalTokens": 1540
},
"intermediateSteps": null
}
When returnIntermediateSteps is true:
{
"output": "The Q3 revenue was $4.2M, up 18% from Q2.",
"operation": "tools",
"iterationsUsed": 3,
"durationMs": 4120,
"totalUsage": { "promptTokens": 1200, "completionTokens": 340, "totalTokens": 1540 },
"intermediateSteps": [
{
"iterationNumber": 1,
"assistantText": null,
"toolCalls": [
{ "toolCallId": "call_abc1", "toolName": "database_query",
"input": { "query": "SELECT SUM(revenue) FROM orders WHERE quarter='Q3'" } }
],
"toolResults": [
{ "toolCallId": "call_abc1", "toolName": "database_query", "output": "4200000" }
],
"usage": { "promptTokens": 400, "completionTokens": 80, "totalTokens": 480 },
"durationMs": 1340
}
]
}
Expression Reference
| Expression | Returns |
|---|---|
{{ $output.agentNode.output }} | Final agent response text string. |
{{ $output.agentNode.operation }} | Agent type that handled the run ("tools", "sql", etc.). |
{{ $output.agentNode.iterationsUsed }} | Number of reasoning iterations consumed. |
{{ $output.agentNode.durationMs }} | Wall-clock execution time in milliseconds. |
{{ $output.agentNode.totalUsage.totalTokens }} | Total tokens consumed across all iterations. |
{{ $output.agentNode.totalUsage.promptTokens }} | Total prompt tokens consumed. |
{{ $output.agentNode.totalUsage.completionTokens }} | Total completion tokens generated. |
{{ $output.agentNode.intermediateSteps[0].toolCalls[0].toolName }} | Name of the first tool called in the first iteration. |
{{ $output.agentNode.intermediateSteps[0].toolResults[0].output }} | Output returned by the first tool in the first iteration. |
{{ $output.agentNode.sessionId }} | Session ID used for memory, or null if memory is disabled. |
Node Policies & GuardRails
| Policy | Detail |
|---|---|
| Max iterations enforcement | Hard cap of 1–50 iterations prevents runaway loops. Agent fails to error port with MAX_ITERATIONS_REACHED code when the limit is hit. Start conservative (5–10) in production and increase only if needed. |
| Token budget | maxTokens limits each individual LLM call. Total token spend scales with iteration count; monitor totalUsage.totalTokens across runs to detect unexpected growth. |
| Tool call allowlisting | Only tools explicitly listed in enabledTools are made available to the agent. The LLM never receives definitions for tools it is not permitted to call. |
| HTTP request domain restriction | The httpRequest tool is constrained to domains listed in toolHttpRequestAllowedDomains. Calls to unlisted domains are rejected before execution. |
| SQL read-only enforcement | When sqlReadOnly is true (default), the SQL agent parser rejects any non-SELECT statement before database execution. Prevents accidental data mutation. |
| Credential rotation | LLM API keys are stored in the BizFirst Credentials Manager and never embedded in node config. Rotate keys without modifying workflows. |
| Prompt injection protection | User-supplied input injected into prompt via {{ expressions }} is treated as data, not instruction. System prompt and user prompt are kept in separate message roles to limit injection surface. |
| Memory isolation per session | Memory is scoped to the sessionId key. Different users or tenants with different session IDs cannot access each other's conversation history. |
| Audit logging of tool calls | Every tool invocation — name, input, output, and timing — is recorded in the execution trace and included in intermediateSteps when enabled. Feed this to your monitoring system for compliance and debugging. |
Examples
Example 1 — Conversational Customer Support with Tools
A customer sends a message. The agent uses its tools to look up the order and generate a personalised reply, maintaining conversation history in Redis across multiple messages.
{
"nodeType": "flow-ai-agent",
"agentType": "conversational",
"llmProvider": "anthropic",
"llmCredentialId": "42",
"llmModelId": "claude-sonnet-4-6",
"systemMessage": "You are a friendly and professional customer support agent for Acme Corp. Check order status before responding to shipping inquiries. Keep replies under 150 words.",
"prompt": "{{ $input.customerMessage }}",
"enabledTools": "lookupOrder,searchFAQ,sendEmail",
"maxIterations": 6,
"temperature": 0.3,
"memoryBackend": "redis",
"sessionId": "{{ $input.customerId }}",
"memoryWindowSize": 8
}
The agent loads the last 8 turns from Redis for this customer, calls lookupOrder to check status, and composes a reply referencing order details.
Example 2 — SQL Agent for Business Analytics
A business analyst asks a natural language question about sales. The SQL agent connects to the reporting database, introspects the schema, generates a query, runs it, and returns formatted results.
{
"nodeType": "flow-ai-agent",
"agentType": "sql",
"llmProvider": "openai",
"llmCredentialId": "17",
"llmModelId": "gpt-4o",
"prompt": "{{ $input.analystQuestion }}",
"systemMessage": "You are a data analyst assistant. Format all monetary values in USD with 2 decimal places. Always include row count in your summary.",
"sqlConnectionString": "{{ $credentials.reportingDb }}",
"sqlProvider": "postgres",
"sqlReadOnly": true,
"sqlTopK": 100,
"sqlAllowedTables": "orders,products,customers,regions",
"sqlIncludeSchema": true,
"temperature": 0.0,
"maxIterations": 5
}
Example question: "What were the top 5 products by revenue in Q3 2025 broken down by region?" — the agent writes the appropriate JOIN query, executes it, and returns a human-readable summary plus the raw data.
Example 3 — PlanExecute Agent for Multi-Step Research
A market research task requires searching multiple sources, synthesising information, and writing a structured report. The planExecute agent generates a complete plan first, then executes each step systematically.
{
"nodeType": "flow-ai-agent",
"agentType": "planExecute",
"llmProvider": "anthropic",
"llmCredentialId": "42",
"llmModelId": "claude-opus-4",
"systemMessage": "You are a professional market analyst. Structure your final report with sections: Executive Summary, Market Overview, Key Players, Opportunities, Risks.",
"prompt": "Research the competitive landscape for {{ $input.marketSegment }} in {{ $input.targetRegion }} and produce a structured analysis report.",
"enabledTools": "webSearch,httpRequest,ragQuery",
"toolHttpRequestAllowedDomains": "api.statista.com,data.worldbank.org",
"maxIterations": 20,
"temperature": 0.4,
"returnIntermediateSteps": true,
"memoryBackend": "inMemory"
}
The agent first outputs a plan: 1. Search for market size data, 2. Identify top competitors, 3. Query internal knowledge base for past analysis, 4. Synthesise findings, 5. Write report. Then it executes each step in sequence, using intermediate results to inform later steps.
maxIterations conservatively (5–10) in production. Monitor totalUsage.totalTokens in your observability system and alert if an agent run exceeds your per-invocation budget. Use smaller models (claude-haiku-3-5, gpt-4o-mini) for high-volume simpler tasks.
returnIntermediateSteps: true during development and testing to see exactly what the agent thought and what each tool returned at every iteration. In production, disable it to reduce output payload size — but always log iterationsUsed, totalUsage.totalTokens, and durationMs to your monitoring system.