TurfAI Task Types Reference
Synced from the TurfAI source on 2026-06-21.
Complete reference for all available task types in TurfAI workflows.
Overview
Task types are the building blocks of TurfAI workflows. Each task type performs a specific operation and can be connected to form complex automation pipelines.
API Endpoint: GET /api/workflows/task-types
Categories
| Category | Description | Task Types |
|---|---|---|
| AI Operations | ML-powered document processing | classification, extraction, llm, summarization, classify_and_extract, rag_enable, rag_query |
| Google Integrations | Google Drive/Gmail operations | google_drive_fetch |
| External Integrations | HTTP API calls | rest_api |
| Communication | Email/notifications | email_send |
| Workflow Control | Flow control primitives | decision, wait |
Core Integration Tasks
These are the most commonly used task types for workflow integrations.
google_drive_fetch_task
Fetch files from Google Drive and import to GCS.
Processor: google_drive_fetch
Use Cases:
- Fetch job descriptions from shared folders
- Download resumes submitted via forms
- Import policy documents for RAG indexing
Configuration
{
"task_type": "google_drive_fetch_task",
"config": {
"file_id": "1ABC123xyz"
}
}Config Options:
| Field | Type | Required | Description |
|---|---|---|---|
file_id | string | One of | Direct Google Drive file ID |
folder_id | string | One of | Folder ID for search mode |
file_name | string | With folder_id | File name to search for |
Modes:
- Direct: Provide
file_idto fetch specific file - Search: Provide
folder_id+file_nameto find file in folder
Output
{
"file_url": "gs://turfdms/documents/123/file.pdf",
"file_id": "1ABC123xyz",
"file_name": "Resume_JohnDoe.pdf",
"mime_type": "application/pdf",
"size": 245789,
"document_id": 123
}Example Node
{
"id": "fetch-resume",
"type": "google_drive_fetch_task",
"data": {
"label": "Fetch Resume from Drive",
"task_type": "google_drive_fetch_task",
"config": {
"file_id": "{{resume_file_id}}"
}
}
}rest_api_task
Make HTTP requests to external APIs with template variable support.
Processor: rest_api
Use Cases:
- Fetch configuration from external services
- Post results to external systems
- Integrate with third-party APIs
- Call internal TurfAI endpoints
Configuration
{
"task_type": "rest_api_task",
"config": {
"url": "http://localhost:9005/roles/{{role_id}}",
"method": "GET",
"timeout": 30,
"output_mapping": {
"jd_file_id": "$.data.jd_file_id",
"hiring_manager_email": "$.data.hiring_manager_email"
}
}
}Config Options:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Yes | - | API URL (supports {{variable}} templates) |
method | string | No | GET | HTTP method |
headers | object | No | {} | Request headers (supports templates) |
body | object | No | - | Request body for POST/PUT/PATCH |
timeout | number | No | 30 | Timeout in seconds |
output_mapping | object | No | - | JSONPath mappings for response extraction |
Template Variables
URLs, headers, and body values support {{variable}} syntax:
{
"url": "https://api.example.com/users/{{user_id}}/documents",
"headers": {
"Authorization": "Bearer {{api_token}}"
},
"body": {
"name": "{{candidate_name}}",
"email": "{{email}}"
}
}Output Mapping (JSONPath)
Extract specific fields from the response:
{
"output_mapping": {
"extracted_name": "$.data.user.name",
"first_item": "$.items[0].id",
"nested_value": "$.response.metadata.count"
}
}Output
{
"data": {
"jd_file_id": "1ABC123xyz",
"hiring_manager_email": "manager@company.com"
},
"status_code": 200,
"_raw_response": { ... }
}Example: Fetch Role Configuration
{
"id": "fetch-role-config",
"type": "rest_api_task",
"data": {
"label": "Fetch Role Configuration",
"task_type": "rest_api_task",
"config": {
"url": "http://localhost:9005/roles/{{role_id}}",
"method": "GET",
"output_mapping": {
"jd_file_id": "$.data.jd_file_id",
"hiring_manager_email": "$.data.hiring_manager_email",
"hr_email": "$.data.hr_email"
}
}
}
}email_send_task
Send emails with HTML support and template variables.
Processor: email_send
Use Cases:
- Send job match notifications
- Deliver workflow results
- Send policy update confirmations
- Notify stakeholders
Configuration
{
"task_type": "email_send_task",
"config": {
"to": ["{{hiring_manager_email}}", "hr@company.com"],
"cc": ["{{recruiter_email}}"],
"subject": "New Application: {{candidate_name}} for {{position}}",
"body": "<h2>Application Received</h2><p>Candidate: {{candidate_name}}</p><p>Match Score: {{match_score}}%</p>",
"html": true
}
}Config Options:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
from | string | No | System default | Sender email |
to | array | Yes | - | Recipient emails (supports templates) |
cc | array | No | [] | CC recipients |
bcc | array | No | [] | BCC recipients |
subject | string | Yes | - | Email subject (supports templates) |
body | string | Yes | - | Email body (supports templates) |
html | boolean | No | true | Send as HTML |
Output
{
"sent": true,
"recipients": ["manager@company.com", "hr@company.com"],
"timestamp": "2024-11-24T10:30:00.000Z"
}Example: Notification Email
{
"id": "send-notification",
"type": "email_send_task",
"data": {
"label": "Send Match Notification",
"task_type": "email_send_task",
"config": {
"to": ["{{hiring_manager_email}}"],
"subject": "New Application Match: {{candidate_name}}",
"body": "<h2>New Job Application</h2><p><strong>Candidate:</strong> {{candidate_name}}</p><p><strong>Position:</strong> {{position}}</p><p><strong>Match Score:</strong> {{match_score}}%</p><h3>Summary</h3><p>{{ai_summary}}</p>",
"html": true
}
}
}wait_task
Poll an endpoint until a condition is met. Generic async wait primitive.
Processor: wait
Use Cases:
- Wait for RAG indexing to complete
- Poll external job status
- Wait for approval workflows
- Monitor async processing
Configuration
{
"task_type": "wait_task",
"config": {
"endpoint": "/api/internal/documents/{{document_id}}/rag-status",
"method": "GET",
"watch_field": "rag_processing_status",
"success_value": "completed",
"failure_values": ["failed", "error"],
"poll_interval": 3,
"timeout": 120
}
}Config Options:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
endpoint | string | Yes | - | URL to poll (supports templates) |
method | string | No | GET | HTTP method |
watch_field | string | Yes | - | Field to monitor (dot notation supported) |
success_value | string | No | "completed" | Value indicating success |
failure_values | array | No | ["failed", "error"] | Values indicating failure |
poll_interval | number | No | 3 | Seconds between polls |
timeout | number | No | 120 | Maximum wait time in seconds |
Output
{
"status": "success",
"final_value": "completed",
"response": { ... },
"elapsed_seconds": 45
}Example: Wait for RAG Indexing
{
"id": "wait-for-rag",
"type": "wait_task",
"data": {
"label": "Wait for RAG Completion",
"task_type": "wait_task",
"config": {
"endpoint": "/api/internal/documents/{{document_id}}/rag-status",
"watch_field": "rag_processing_status",
"success_value": "completed",
"failure_values": ["failed"],
"poll_interval": 5,
"timeout": 300
}
}
}AI Operations Tasks
classification_task
Classify documents into categories using AI.
Processor: classification
Configuration
| Field | Type | Default | Description |
|---|---|---|---|
classification_type | string | "document_type" | Type: document_type, sentiment, topic |
include_confidence | boolean | true | Include confidence scores |
return_multiple | boolean | false | Return multiple classifications |
Input
| Field | Type | Required | Description |
|---|---|---|---|
file_url | string | Yes | GCS URL of document |
metadata | object | No | Additional context |
Output
{
"prompt_title": "Resume Classification",
"section": "HR Documents",
"confidence": 0.95,
"classification": {
"type": "resume",
"subtype": "technical"
}
}extraction_task
Extract structured data from documents.
Processor: document_extraction
Configuration
| Field | Type | Default | Description |
|---|---|---|---|
prompt_id | string | - | Prompt ID to use |
model_type | string | "vertex" | LLM: vertex, openai, anthropic |
output_format | string | "json" | Output: json, text |
use_classification_prompt | boolean | false | Use prompt from classification |
Input
| Field | Type | Required | Description |
|---|---|---|---|
file_url | string | Yes | GCS URL of document |
prompt_data | object | No | Prompt override |
Output
{
"extraction_result": {
"name": "John Doe",
"email": "john@example.com",
"skills": ["Python", "Machine Learning"],
"experience_years": 5
},
"confidence": 0.92,
"tokens_used": 1250
}llm_task
Generic LLM-powered text processing.
Processor: llm_task
Configuration
| Field | Type | Default | Description |
|---|---|---|---|
prompt_id | string | - | Use predefined prompt |
prompt_text | string | - | Custom prompt text |
model_type | string | "vertex" | LLM provider |
process_combined_inputs | boolean | true | Combine all inputs |
output_format | string | "json" | Output format |
Input
| Field | Type | Required | Description |
|---|---|---|---|
file_url | string | No | Document URL |
prompt_data | object | No | Prompt variables |
text_input | string | No | Direct text input |
Output
{
"result": { ... },
"tokens_used": 850
}summarization_task
Generate document summaries.
Processor: summarization
Configuration
| Field | Type | Default | Description |
|---|---|---|---|
summary_type | string | "brief" | Type: brief, detailed, bullet_points |
max_length | number | 500 | Max words |
Output
{
"summary": "This resume belongs to a senior software engineer with 5 years of experience in Python and machine learning...",
"word_count": 150
}classify_and_extract
Combined classification and extraction in one step.
Processor: classify_and_extract
Configuration
| Field | Type | Default | Description |
|---|---|---|---|
classification_type | string | "document_type" | Classification type |
extract_after_classify | boolean | true | Run extraction after |
Output
{
"classification": {
"type": "resume",
"confidence": 0.95
},
"extraction_result": {
"name": "John Doe",
"skills": ["Python", "ML"]
}
}rag_enable_task
Enable RAG indexing for a document.
Processor: rest_api (calls internal endpoint)
Configuration
Default configuration calls /api/internal/rag/enable:
{
"url": "http://localhost:1338/api/internal/rag/enable",
"method": "POST",
"body": {
"document_id": "{{document_id}}",
"user_id": "{{user_id}}",
"force_reprocess": false
}
}Input
| Field | Type | Required | Description |
|---|---|---|---|
document_id | number | Yes | From previous node (e.g., drive fetch) |
user_id | number | Yes | From workflow context |
Output
{
"rag_status": "queued",
"rag_job_id": "rag-embed-123-1700000000"
}rag_query_task
Query the RAG knowledge base.
Processor: rest_api (calls internal endpoint)
Configuration
Default configuration calls /api/internal/rag/query:
{
"url": "http://localhost:1338/api/internal/rag/query",
"method": "POST",
"body": {
"query": "{{query}}",
"user_id": "{{user_id}}",
"top_k": 5
}
}Input
| Field | Type | Required | Description |
|---|---|---|---|
query | string | Yes | Search query |
user_id | number | Yes | From workflow context |
Output
{
"answer": "According to the Remote Work Policy document, employees can work remotely up to 3 days per week...",
"sources": [
{
"document_id": 45,
"document_name": "Remote Work Policy.pdf",
"snippet": "...employees may work from home up to three days...",
"score": 0.92
}
],
"session_id": "sess-abc123"
}Workflow Examples
F1: Job Application Notification
{
"nodes": [
{
"id": "1",
"type": "rest_api_task",
"data": {
"label": "Fetch Role Config",
"config": {
"url": "http://localhost:9005/roles/{{role_id}}",
"output_mapping": {
"jd_file_id": "$.data.jd_file_id",
"hiring_manager_email": "$.data.hiring_manager_email"
}
}
}
},
{
"id": "2",
"type": "google_drive_fetch_task",
"data": {
"label": "Fetch JD",
"config": { "file_id": "{{jd_file_id}}" }
}
},
{
"id": "3",
"type": "google_drive_fetch_task",
"data": {
"label": "Fetch Resume",
"config": { "file_id": "{{resume_file_id}}" }
}
},
{
"id": "4",
"type": "extraction_task",
"data": {
"label": "Extract Resume",
"config": { "output_format": "json" }
}
},
{
"id": "5",
"type": "llm_task",
"data": {
"label": "Calculate Match",
"config": {
"prompt_text": "Compare this resume to the job description and provide a match score..."
}
}
},
{
"id": "6",
"type": "email_send_task",
"data": {
"label": "Notify Hiring Manager",
"config": {
"to": ["{{hiring_manager_email}}"],
"subject": "New Application: {{candidate_name}}",
"body": "<h2>Match Score: {{match_score}}%</h2>..."
}
}
}
]
}F4-A: HR Policy Ingestion
{
"nodes": [
{
"id": "1",
"type": "google_drive_fetch_task",
"data": {
"label": "Fetch Policy Doc",
"config": { "file_id": "{{policy_file_id}}" }
}
},
{
"id": "2",
"type": "rag_enable_task",
"data": {
"label": "Enable RAG"
}
},
{
"id": "3",
"type": "wait_task",
"data": {
"label": "Wait for Indexing",
"config": {
"endpoint": "/api/internal/documents/{{document_id}}/rag-status",
"watch_field": "rag_processing_status",
"success_value": "completed",
"timeout": 300
}
}
},
{
"id": "4",
"type": "email_send_task",
"data": {
"label": "Send Confirmation",
"config": {
"to": ["{{notification_email}}"],
"subject": "Policy Indexed: {{policy_name}}",
"body": "The policy document has been indexed and is now searchable."
}
}
}
]
}F4-B: Employee Q&A
{
"nodes": [
{
"id": "1",
"type": "rag_query_task",
"data": {
"label": "Query Knowledge Base",
"config": {
"body": {
"query": "{{question}}",
"user_id": "{{user_id}}",
"top_k": 5
}
}
}
},
{
"id": "2",
"type": "email_send_task",
"data": {
"label": "Send Answer",
"config": {
"to": ["{{employee_email}}"],
"subject": "Answer to your question",
"body": "<p>{{answer}}</p><h3>Sources</h3>{{sources}}"
}
}
}
]
}Template Variables
All task types support {{variable}} template syntax for dynamic values.
Sources of Variables
- Webhook Payload: Data sent to trigger endpoint
- Previous Node Outputs: Results from upstream nodes
- Workflow Context:
user_id,execution_id, etc.
Example Flow
Webhook payload: { "candidate_name": "John", "role_id": "engineer" }
↓
Node 1 (rest_api_task): Uses {{role_id}} → outputs { "jd_file_id": "ABC123" }
↓
Node 2 (google_drive_fetch_task): Uses {{jd_file_id}} → outputs { "file_url": "gs://..." }
↓
Node 3 (email_send_task): Uses {{candidate_name}}, {{file_url}}Error Handling
Task Failure
When a task fails, the workflow execution status becomes failed:
{
"status": "failed",
"error": "REST API call failed: 404 Not Found",
"failed_node": "fetch-role-config",
"task_states": {
"fetch-role-config": {
"status": "failed",
"error": "404 Not Found"
}
}
}Timeout Handling
The wait_task returns failure status on timeout:
{
"status": "failure",
"final_value": "processing",
"elapsed_seconds": 120,
"error": "Timeout waiting for completion"
}Control Flow Tasks
decision
NEW in v1.1 - Conditional branching based on runtime evaluation.
Evaluates a condition and directs workflow execution down one of two paths (true or false). Enables dynamic workflow behavior based on previous task outputs.
Processor: decision (alias: decision_task)
Use Cases:
- Route documents based on classification results
- Handle different document types with separate processing paths
- Conditional approval workflows
- Dynamic email routing based on content analysis
- Skip processing steps based on validation results
Configuration
{
"task_type": "decision",
"config": {
"operator": "==",
"left_operand": "$.classification.type",
"right_operand": "Invoice",
"true_label": "true",
"false_label": "false"
}
}Config Options:
| Field | Type | Required | Description |
|---|---|---|---|
operator | string | Yes | Comparison operator: ==, !=, >, <, >=, <=, in, contains, matches |
left_operand | string | Yes | JSONPath expression (e.g., $.classification.type) or literal value |
right_operand | string/number/boolean | Yes | Value to compare against (can be literal or JSONPath) |
true_label | string | No | Label for true path (default: "true") |
false_label | string | No | Label for false path (default: "false") |
Supported Operators:
| Operator | Description | Example |
|---|---|---|
== | Equals | $.type == "Invoice" |
!= | Not equals | $.status != "processed" |
> | Greater than | $.amount > 1000 |
< | Less than | $.confidence < 0.8 |
>= | Greater or equal | $.score >= 90 |
<= | Less or equal | $.priority <= 5 |
in | Left in right (array/string) | "pdf" in $.allowed_types |
contains | Right in left (array/string) | $.tags contains "urgent" |
matches | Regex match | $.email matches ".*@company.com" |
JSONPath Support
Use JSONPath expressions to reference outputs from previous tasks:
$.task_name.field_nameExamples:
$.classification.type- Access classification result$.extraction.invoice_amount- Access extracted field$.email.to- Access email configuration- Literal values:
"Invoice",1000,true
Output
{
"result": true,
"branch": "true",
"decision": "true",
"active_path": "true",
"condition": {
"operator": "==",
"left_operand": "$.classification.type",
"right_operand": "Invoice",
"left_value": "Invoice",
"right_value": "Invoice"
}
}Output Fields:
| Field | Type | Description |
|---|---|---|
result | boolean | Condition evaluation result |
branch | string | Selected branch label |
decision | string | "true" or "false" |
active_path | string | Path taken by execution |
condition | object | Details about evaluated condition |
Edge Configuration
Decision nodes MUST have exactly 2 outgoing edges:
- True Edge: Label =
"true"(or customtrue_label) - False Edge: Label =
"false"(or customfalse_label)
Frontend: When connecting edges from a decision node:
- Click the edge to select it
- Set the edge
labelproperty to"true"or"false" - The workflow executor uses this label to activate/deactivate paths
Example: Document Type Routing
{
"nodes": [
{
"id": "classify",
"type": "classification_task",
"data": {
"label": "Classify Document",
"task_type": "classification_task",
"config": {
"category": "document_type"
}
}
},
{
"id": "decision",
"type": "decision",
"data": {
"label": "Is Invoice?",
"task_type": "decision",
"config": {
"operator": "==",
"left_operand": "$.classify.type",
"right_operand": "Invoice"
}
}
},
{
"id": "process-invoice",
"type": "extraction_task",
"data": {
"label": "Extract Invoice Data",
"task_type": "extraction_task",
"config": {
"prompt_id": 42
}
}
},
{
"id": "process-other",
"type": "summarization_task",
"data": {
"label": "Summarize Document",
"task_type": "summarization_task",
"config": {
"type": "brief"
}
}
}
],
"edges": [
{ "source": "classify", "target": "decision" },
{
"source": "decision",
"target": "process-invoice",
"sourceHandle": "true",
"label": "true"
},
{
"source": "decision",
"target": "process-other",
"sourceHandle": "false",
"label": "false"
}
]
}Workflow Execution Behavior
- Decision node executes - Evaluates condition
- Edge activation - Marks one edge as active based on result
- Path execution - Only nodes on active path execute
- Skipped nodes - Nodes on inactive path get
status: "skipped" - Convergence - Paths can merge back together downstream
Important: The workflow remains a DAG (Directed Acyclic Graph). Decision nodes create diverging paths, not loops.
Advanced Examples
Numeric Comparison:
{
"operator": ">",
"left_operand": "$.extraction.invoice_amount",
"right_operand": "10000"
}Array Contains:
{
"operator": "contains",
"left_operand": "$.classification.tags",
"right_operand": "urgent"
}Regex Match:
{
"operator": "matches",
"left_operand": "$.extraction.email",
"right_operand": ".*@approved-domain\\.com$"
}Nested Field Access:
{
"operator": "==",
"left_operand": "$.rest_api.response.data.status",
"right_operand": "approved"
}Validation Rules
Backend validation (workflow-validation.js) enforces:
- Decision nodes must have exactly 2 outgoing edges
- Both edges must have labels
- One edge must be labeled "true", one "false"
- Config must include:
operator,left_operand,right_operand
Validation errors will prevent workflow execution.
Frontend Component
- Node Type: Diamond-shaped with orange gradient
- Handles:
- Top: Target (incoming)
- Left: Source (true path, green)
- Right: Source (false path, red)
- Config Panel: Dropdown operators, JSONPath hints, condition preview
Limitations (Phase 1)
- ⚠️ No loops: Workflow must remain acyclic (no cycles allowed)
- ⚠️ Binary branches: Only true/false (multi-way branching not supported)
- ⚠️ Simple conditions: No AND/OR/NOT logic (single comparison only)
Workaround for complex conditions: Chain multiple decision nodes
See Also
- Webhook Integration Guide - Trigger workflows externally
- PLAN_2024_11_24.md - Implementation details