VirtuousAI
Primitives

Actions

Execute and monitor units of work on your connections

Actions

Actions are discrete units of work that execute on connections. They represent the "verbs" of VirtuousAI — the things you want to do with your connected services.

Concept

An action combines:

  • Template — What to do (e.g., dlt_extract, web_search)
  • Connection — Where to connect (credentials)
  • Config — How to do it (parameters)

Examples:

TemplateConnectionConfig
dlt_extractconn_shopify{ resources: ["orders"], incremental: true }
web_searchconn_rest_api{ query: "customer data" }
insight_delegate{ prompt: "Summarize..." }

Action Types

Actions fall into categories based on what they do:

TypeDescriptionExamples
Data SyncsPull data from external services into VirtuousAIdlt_extract from Shopify, Salesforce
TransformationsProcess and transform dataDuckDB queries, aggregations
IntegrationsPush data to destination servicesExport to warehouse, call APIs
AI OperationsLLM-powered operationsinsight_delegate for summarization

Action Lifecycle

StatusDescriptionCan Transition To
PENDINGCreated, awaiting executionRUNNING, CANCELLED, AWAITING_APPROVAL
AWAITING_APPROVALRequires human approvalRUNNING (approved), REJECTED
RUNNINGActively executingCOMPLETED, FAILED, CANCELLED
COMPLETEDFinished successfully— (terminal)
FAILEDEncountered an error— (terminal, can retry)
CANCELLEDManually cancelled— (terminal)
REJECTEDApproval denied— (terminal)

Execution Model

VirtuousAI uses two execution modes:

ModeWhen UsedCharacteristics
SYNCFast operations (under 30s)Inline execution, immediate response
ASYNC_QUEUELong-running operationsSQS + Dramatiq workers, lease-based

Lease-Based Ownership

For ASYNC_QUEUE operations:

  • Lease Duration: 90 seconds
  • Heartbeat Interval: Every 30 seconds
  • Watchdog Grace: 180 seconds before marking abandoned

If a worker crashes, the watchdog detects the stale lease and marks the run as failed, preventing zombie jobs.

ActionRun Structure

Each execution creates an ActionRun — an immutable record:

{
  "id": "run_xyz789",
  "actionId": "action_abc123",
  "status": "COMPLETED",
  "startedAt": "2026-01-22T14:30:00Z",
  "completedAt": "2026-01-22T14:32:15Z",
  "result": {
    "recordsProcessed": 1250,
    "bytesTransferred": 2100000,
    "tables": ["orders", "order_line_items"]
  },
  "artifacts": [
    { "name": "orders.parquet", "size": 1500000 }
  ]
}

ActionRuns are immutable. Even if an action is deleted, historical runs are preserved for auditing.

Creating Actions

{
  "kind": "dlt_extract",
  "connectionRef": { "slug": "shopify" },
  "definition": {
    "source": "shopify",
    "resources": ["orders", "products"],
    "incremental": true,
    "start_date": "2026-01-01"
  }
}
{
  "kind": "insight_delegate",
  "definition": {
    "prompt": "Summarize the key trends in this quarter's sales data",
    "context": "{{previous_step.output}}"
  }
}

Connection Resolution

Actions resolve connections flexibly:

Reference TypeExampleResolution
By ID{ "id": "conn_abc123" }Exact match
By Slug{ "slug": "shopify" }LLM-friendly name lookup
By Provider{ "provider": "shopify" }Uses org's default for provider

Streaming Execution

For long-running actions, subscribe to real-time progress via Server-Sent Events:

GET /api/v1/action-runs/{run_id}/stream
Accept: text/event-stream

Events include:

  • progress — Percentage complete
  • log — Execution log messages
  • complete — Final result
  • error — Failure details

Error Handling

When actions fail, the run includes detailed error information:

{
  "status": "FAILED",
  "error": {
    "code": "CONNECTION_ERROR",
    "message": "Failed to connect to Shopify API",
    "details": {
      "statusCode": 401,
      "shopifyError": "Invalid API key"
    },
    "retryable": true
  }
}

Error Codes

CodeDescriptionRetryable
CONNECTION_ERRORFailed to connect to external serviceUsually yes
AUTH_ERRORAuthentication/authorization failedNo (fix credentials)
RATE_LIMITEDExternal API rate limit hitYes (with backoff)
DATA_ERRORInvalid or corrupt dataNo (fix source data)
TIMEOUTExecution exceeded time limitSometimes
INTERNAL_ERRORUnexpected system errorYes

Retry Behavior

Retryable errors are automatically retried with exponential backoff. Non-retryable errors require manual intervention.

Best Practices

  1. Use incremental syncs — When possible, sync only new/changed data to reduce execution time
  2. Set appropriate timeouts — Configure timeouts based on expected data volume
  3. Monitor runs — Set up alerts for failed actions, especially in automations
  4. Test with small datasets — Validate action configuration before running on full data
  5. Use streaming for long runs — Subscribe to SSE for real-time progress on lengthy operations

OpenAPI Reference

For detailed endpoint schemas, request/response formats, and authentication:

On this page