The runtime is a stateless flow walker in apps/studio-api/app/runtime/engine.py. Each turn loads the published ConversationFlow (or draft in simulator), walks nodes until awaiting input or session end, and returns bot messages plus debug metadata.
Intent matching order
- Welcome event on session start when enabled.
- Small talk topics — pattern score before intents.
- Substring match on training phrases.
- LLM verify — confirm keyword match semantically (fails open on LLM outage).
- LLM match — full intent classifier when substring misses.
- Knowledge fallback — hybrid search when no intent; synthesize answer if score clears threshold.
- Fallback event / fallback intent.
Node types (assistant sub-flows)
| Type | Behavior |
|---|---|
| start / end | Session entry and termination |
| intent | Entry node for matched intent sub-flow |
| message | Bot text; {{ session.var }} templates; rich UI blocks |
| entity | Slot capture with reprompt and max_attempts |
| decision | Expression branch on edges |
| service | HTTP tool — real httpx call, JSONPath outputs |
| python | Sandboxed script — session read/write |
| set | Assign session variable |
| handoff | Human agent transfer |
| fallback | Default branch |
| subflow | Invoke another flow graph |
| knowledge | Hybrid retrieval + optional LLM synthesis from chunks |
| instruction_agent | AgenticLoop — multi-step LLM + tool calls |
instruction_agent nodes
Configured in flow JSON with instructions, tools[], optional model, temperature, max_steps, greeting. Uses AgenticLoop with OpenAI-compatible or Anthropic provider from settings.effective_agent_*. Memory persists under session variable _agent_memory_{nodeId}. ToolBridge executes workspace/agent tools registered on the node.
Knowledge nodes
- Query from static template, last user message, and/or conversation summary (LLM summary when configured).
- Retriever — vector + keyword hybrid (pgvector + tsvector).
- synthesize_answer — uses extraction provider LLM (Groq/OpenAI/Anthropic).
- Respects knowledge_fallback_min_score when used as runtime fallback path.
Service nodes
- Template URL, headers, body with {{ variables }}.
- Workspace secrets resolved at runtime — never stored in flow JSON.
- Retries, timeout, JSONPath mapping to session.*.
- response_body stored on session for simulator trace.
Safety limits
- 64 steps per turn cycle guard.
- Python node wall-clock timeout (PYTHON_NODE_TIMEOUT_SECONDS).
- Free-tier session/import rate limits via usage_events (429 + X-RateLimit-*).
- Monthly LLM spend cap per assistant — blocks enrichment and intent LLM matcher.
Agent-level orchestration
agent_runtime.py sits above engine.py for multi-intent assistants: tracks _active_intent_id, routes utterances to intent sub-flows, returns to root when sub-flow completes, handles welcome/fallback at agent scope.
Workflow graph runtime
Legacy workflows use workflow_graph_runtime.py plus runtime route handlers (not engine.py intent matching). The simulator walks nodes from triggers/root_agent through agents, knowledge, router/decision branches, tool nodes, nested workflow handoffs, and end nodes.
- Routing — select_workflow_successor_node evaluates edge condition.expr against last user text and variables.
- Tool nodes — ToolBridge executes workspace tools; trace event workflow.tool.executed.
- Sub-workflow — workflow nodes load the referenced graph and enter its first runnable node.
- Publish validation — rejects script, datastore, set, human, parallel, wait; requires reachable agent/knowledge/end from entries.
- Chain runtime — workflow_chain_runtime.py runs primitive chains (assistant, agent, webhook, human, decide, notify, schedule) with persisted WorkflowChainRun steps.