Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions examples/agents/workflow-assistant.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
{
"description": "Creates and manages automation workflows",
"displayName": "Automation Assistant",
"maxSteps": 30,
"modelPreset": "advanced",
"outputReserve": 2048,
"roleRestriction": "admin_developer",
"description": "Creates and manages automation workflows",
"systemInstructions": "You are an expert workflow automation assistant. You help users create, modify, and understand their automation workflows.\n\n**KNOWLEDGE SCOPE**\nWorkflows can use: configured integrations (REST API, SQL, OAuth), the organization's knowledge base, and internal CRM data.\n- Integrations must be set up in [Settings > Integrations]({{site_url}}/dashboard/{{organization.id}}/settings/integrations) before they can be used in workflow action steps.\n- Knowledge base documents are managed on the [Documents page]({{site_url}}/dashboard/{{organization.id}}/documents).\nIf the user references an integration that isn't configured, tell them to set it up in Settings > Integrations first.\n\n**CRITICAL: TOOL CALL JSON FORMATTING**\nWhen calling tools, you MUST generate valid JSON:\n1. Use ONLY double quotes (\") for ALL strings - NEVER use single quotes (')\n2. Field names MUST be simple identifiers (e.g., \"config\", \"userPrompt\")\n3. NEVER use descriptive phrases as field names\n4. Escape quotes inside strings: \\\"\n5. Multi-line strings should use \\n for newlines in JSON string values. Inside JEXL template expressions ({{ }}), \\n is also preserved as newlines from JSON parsing\n6. Do NOT include tabs or control characters in strings\n\n**TOOL USAGE GUIDELINES**\nEach tool has detailed instructions in its description. Read them carefully before use.\n- Use workflow_read to get current state before modifications\n- Use workflow_syntax(category='...') when you need syntax details\n\n**⭐ WORKFLOW CREATION CHECKLIST (FOLLOW THIS ORDER)**\nBefore creating a workflow, ALWAYS follow these steps:\n1. □ **Check for existing workflows** - workflow_read(operation='list_all') to check if similar workflow exists\n2. □ If similar workflow exists, ask user: modify existing (click 'Edit' in UI) or create new with different name?\n3. □ Fetch syntax for the step types you need: workflow_syntax(category='action|llm|condition|loop|...')\n3b. □ If workflow uses integrations: workflow_syntax(category='action') shows available integrations. Use integration_introspect for operation parameter details.\n4. □ Use snake_case for stepSlugs (e.g., find_customer, process_order)\n5. □ nextSteps is OUTSIDE config (same level as stepType, config)\n6. □ LLM steps require \"name\" + \"systemPrompt\" (NOT \"prompt\")\n7. □ Action steps require \"type\" in config\n8. □ Entity processing: use workflow_processing_records (find_unprocessed + record_processed) — see category='action'\n9. □ Email sending: use conversation + approval actions, no direct send_email — see category='action'\n10. □ Use loop for data sync iteration, NOT for entity processing\n\n**CORE PHILOSOPHY: LLM-FIRST FOR BUSINESS LOGIC**\nFor workflows with business logic (NOT data sync), treat LLM as the intelligent core:\n- Users describe WHAT they want; AI figures out HOW\n- Give whole records to AI; let AI analyze and decide\n- Action steps = Simple data fetch/store (no logic)\n- LLM steps = All intelligence, decisions, and content generation\n\n**COMMUNICATION RULES**\n- Do NOT restate or list workflow steps — the user can see them\n- Issue reported? Use workflow_read to investigate BEFORE responding\n- Execution output shared? Analyze it — extract IDs, statuses, errors. No generic advice\n- Be specific and actionable, not vague suggestions\n- Don't know? Say so — don't pad with restated information\n- One paragraph max unless the user asks for detail\n- Never mention the position (above/below) of approval cards in the chat UI.\n\n**VERSION STATUS RULES**\n- Draft: editable\n- Active: immutable - tell user to click 'Edit' button to create draft, then ask again\n- Archived: read-only\n\n**WORKFLOW CONTEXT AWARENESS**\nWhen \"Current Workflow Context\" is provided, you are editing THAT specific workflow.\nDo NOT ask \"create new or update existing?\" - always edit the current workflow.\nUse the provided Workflow ID for all updates.",
"timeoutMs": 240000,
"toolNames": [
"workflow_read",
"workflow_syntax",
Expand All @@ -17,5 +12,10 @@
"integration_introspect",
"run_workflow"
],
"visibleInChat": false
"modelPreset": "advanced",
"maxSteps": 30,
"timeoutMs": 240000,
"outputReserve": 2048,
"roleRestriction": "admin_developer",
"visibleInChat": true
}
1 change: 1 addition & 0 deletions examples/workflows/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.history/
165 changes: 102 additions & 63 deletions examples/workflows/circuly/sync-customers.json
Original file line number Diff line number Diff line change
@@ -1,160 +1,199 @@
{
"workflowConfig": {
"name": "Circuly Customers Sync",
"description": "Synchronize customers from Circuly to local database with pagination",
"version": "2.0.0",
"workflowType": "predefined",
"config": {
"timeout": 300000,
"retryPolicy": { "maxRetries": 3, "backoffMs": 2000 },
"variables": {
"organizationId": "org_demo",
"pageSize": 50,
"maxPages": 20,
"currentPage": 1
}
"name": "Circuly Customers Sync",
"description": "Synchronize customers from Circuly to local database with pagination",
"version": "1.0.0",
"enabled": true,
"config": {
"timeout": 300000,
"retryPolicy": {
"maxRetries": 3,
"backoffMs": 2000
},
"variables": {
"currentPage": 1,
"maxPages": 20,
"organizationId": "org_demo",
"pageSize": 50
}
},
"stepsConfig": [
"steps": [
{
"stepSlug": "start",
"name": "start",
"stepType": "start",
"order": 0,
"config": {},
"nextSteps": { "success": "fetch_customers" }
"nextSteps": {
"success": "fetch_customers"
}
},
{
"stepSlug": "fetch_customers",
"name": "Fetch Customers from Circuly",
"stepType": "action",
"order": 1,
"config": {
"type": "integration",
"parameters": {
"name": "circuly",
"operation": "list_customers",
"params": {
"page": "{{currentPage}}",
"per_page": "{{pageSize}}",
"sort": "created_at",
"desc": false
"desc": false,
"page": "{{config.currentPage}}",
"per_page": "{{config.pageSize}}",
"sort": "created_at"
}
}
},
"type": "integration"
},
"nextSteps": { "success": "loop_customers" }
"nextSteps": {
"success": "loop_customers"
}
},
{
"stepSlug": "loop_customers",
"name": "Loop Through Customers",
"stepType": "loop",
"order": 2,
"config": {
"items": "{{steps.fetch_customers.output.data.result.data}}",
"itemVariable": "customer"
"itemVariable": "customer",
"items": "{{steps.fetch_customers.output.data.result.data}}"
},
"nextSteps": { "loop": "query_existing_customer", "done": "check_has_next_page" }
"nextSteps": {
"done": "check_has_next_page",
"loop": "query_existing_customer"
}
},
{
"stepSlug": "query_existing_customer",
"name": "Query Existing Customer",
"stepType": "action",
"order": 3,
"config": {
"type": "customer",
"parameters": {
"operation": "query",
"externalId": "{{loop.item.id}}",
"paginationOpts": { "numItems": 1, "cursor": null }
}
"operation": "query",
"paginationOpts": {
"cursor": null,
"numItems": 1
}
},
"type": "customer"
},
"nextSteps": { "success": "check_customer_exists" }
"nextSteps": {
"success": "check_customer_exists"
}
},
{
"stepSlug": "check_customer_exists",
"name": "Check Customer Exists",
"stepType": "condition",
"order": 4,
"config": {
"expression": "steps.query_existing_customer.output.data.page|length > 0",
"description": "Check if customer already exists in database"
"description": "Check if customer already exists in database",
"expression": "steps.query_existing_customer.output.data.items|length > 0"
},
"nextSteps": { "true": "update_existing_customer", "false": "insert_new_customer" }
"nextSteps": {
"false": "insert_new_customer",
"true": "update_existing_customer"
}
},
{
"stepSlug": "update_existing_customer",
"name": "Update Existing Customer",
"stepType": "action",
"order": 5,
"config": {
"type": "customer",
"parameters": {
"customerId": "{{steps.query_existing_customer.output.data.items[0]._id}}",
"operation": "update",
"customerId": "{{steps.query_existing_customer.output.data.page[0]._id}}",
"updates": {
"name": "{{loop.item.first_name}} {{loop.item.last_name}}",
"email": "{{loop.item.email}}",
"address": {
"street": "{{loop.item.address.shipping.street}}",
"city": "{{loop.item.address.shipping.city}}",
"country": "{{loop.item.address.shipping.country}}",
"postalCode": "{{loop.item.address.shipping.postal_code}}"
"postalCode": "{{loop.item.address.shipping.postal_code}}",
"street": "{{loop.item.address.shipping.street}}"
},
"status": "active",
"source": "circuly",
"email": "{{loop.item.email}}",
"locale": "{{loop.item.default_locale}}",
"metadata": {
"circuly": "{{loop.item}}",
"syncedAt": "{{now}}"
}
},
"name": "{{loop.item.first_name}} {{loop.item.last_name}}",
"source": "circuly",
"status": "active"
}
}
},
"type": "customer"
},
"nextSteps": { "success": "loop_customers" }
"nextSteps": {
"success": "loop_customers"
}
},
{
"stepSlug": "insert_new_customer",
"name": "Insert New Customer",
"stepType": "action",
"order": 6,
"config": {
"type": "customer",
"parameters": {
"operation": "create",
"name": "{{loop.item.first_name}} {{loop.item.last_name}}",
"email": "{{loop.item.email}}",
"address": {
"street": "{{loop.item.address.shipping.street}}",
"city": "{{loop.item.address.shipping.city}}",
"country": "{{loop.item.address.shipping.country}}",
"postalCode": "{{loop.item.address.shipping.postal_code}}"
"postalCode": "{{loop.item.address.shipping.postal_code}}",
"street": "{{loop.item.address.shipping.street}}"
},
"email": "{{loop.item.email}}",
"externalId": "{{loop.item.id}}",
"status": "active",
"source": "circuly",
"locale": "{{loop.item.default_locale}}",
"metadata": {
"circuly": "{{loop.item}}",
"syncedAt": "{{now}}"
}
}
},
"name": "{{loop.item.first_name}} {{loop.item.last_name}}",
"operation": "create",
"source": "circuly",
"status": "active"
},
"type": "customer"
},
"nextSteps": { "success": "loop_customers" }
"nextSteps": {
"success": "loop_customers"
}
},
{
"stepSlug": "check_has_next_page",
"name": "Check Has Next Page",
"stepType": "condition",
"order": 7,
"config": {
"expression": "steps.fetch_customers.output.data.result.pagination.hasNextPage == true && currentPage < maxPages",
"description": "Check if Circuly has more pages and we have not exceeded max page limit"
"description": "Check if Circuly has more pages and we have not exceeded max page limit",
"expression": "steps.fetch_customers.output.data.result.pagination.hasNextPage == true && config.currentPage < config.maxPages"
},
"nextSteps": { "true": "prepare_next_page", "false": "noop" }
"nextSteps": {
"false": "noop",
"true": "prepare_next_page"
}
},
{
"stepSlug": "prepare_next_page",
"name": "Prepare Next Page",
"stepType": "action",
"order": 8,
"config": {
"type": "set_variables",
"parameters": {
"variables": [{ "name": "currentPage", "value": "{{currentPage + 1}}" }]
}
"variables": [
{
"name": "currentPage",
"value": "{{config.currentPage + 1}}"
}
]
},
"type": "set_variables"
},
"nextSteps": { "success": "fetch_customers" }
"nextSteps": {
"success": "fetch_customers"
}
}
]
}
Loading