# Action Management API This document describes the Action Management API endpoints for the Attune automation platform. ## Overview Actions are the executable units in Attune that perform specific tasks. Each action belongs to a pack and can have parameters, output schemas, and runtime requirements. **Base Path:** `/api/v1/actions` ## Data Model ### Action ```json { "id": 1, "ref": "core.http.get", "pack": 1, "pack_ref": "core", "label": "HTTP GET Request", "description": "Performs an HTTP GET request to a specified URL", "entrypoint": "/actions/http_get.py", "runtime": 1, "param_schema": { "type": "object", "properties": { "url": { "type": "string" }, "headers": { "type": "object" } }, "required": ["url"] }, "out_schema": { "type": "object", "properties": { "status_code": { "type": "integer" }, "body": { "type": "string" } } }, "created": "2024-01-13T10:00:00Z", "updated": "2024-01-13T10:00:00Z" } ``` ### Action Summary (List View) ```json { "id": 1, "ref": "core.http.get", "pack_ref": "core", "label": "HTTP GET Request", "description": "Performs an HTTP GET request to a specified URL", "entrypoint": "/actions/http_get.py", "runtime": 1, "created": "2024-01-13T10:00:00Z", "updated": "2024-01-13T10:00:00Z" } ``` ## Endpoints ### List All Actions Retrieve a paginated list of all actions. **Endpoint:** `GET /api/v1/actions` **Query Parameters:** - `page` (integer, optional): Page number (default: 1) - `per_page` (integer, optional): Items per page (default: 20, max: 100) **Response:** `200 OK` ```json { "data": [ { "id": 1, "ref": "core.http.get", "pack_ref": "core", "label": "HTTP GET Request", "description": "Performs an HTTP GET request", "entrypoint": "/actions/http_get.py", "runtime": 1, "created": "2024-01-13T10:00:00Z", "updated": "2024-01-13T10:00:00Z" } ], "pagination": { "page": 1, "per_page": 20, "total": 1, "total_pages": 1 } } ``` --- ### List Actions by Pack Retrieve all actions belonging to a specific pack. **Endpoint:** `GET /api/v1/packs/:pack_ref/actions` **Path Parameters:** - `pack_ref` (string): Pack reference identifier **Query Parameters:** - `page` (integer, optional): Page number (default: 1) - `per_page` (integer, optional): Items per page (default: 20, max: 100) **Response:** `200 OK` ```json { "data": [ { "id": 1, "ref": "core.http.get", "pack_ref": "core", "label": "HTTP GET Request", "description": "Performs an HTTP GET request", "entrypoint": "/actions/http_get.py", "runtime": 1, "created": "2024-01-13T10:00:00Z", "updated": "2024-01-13T10:00:00Z" } ], "pagination": { "page": 1, "per_page": 20, "total": 1, "total_pages": 1 } } ``` **Errors:** - `404 Not Found`: Pack with the specified ref does not exist --- ### Get Action by Reference Retrieve a single action by its reference identifier. **Endpoint:** `GET /api/v1/actions/:ref` **Path Parameters:** - `ref` (string): Action reference identifier (e.g., "core.http.get") **Response:** `200 OK` ```json { "data": { "id": 1, "ref": "core.http.get", "pack": 1, "pack_ref": "core", "label": "HTTP GET Request", "description": "Performs an HTTP GET request to a specified URL", "entrypoint": "/actions/http_get.py", "runtime": 1, "param_schema": { ... }, "out_schema": { ... }, "created": "2024-01-13T10:00:00Z", "updated": "2024-01-13T10:00:00Z" } } ``` **Errors:** - `404 Not Found`: Action with the specified ref does not exist --- ### Create Action Create a new action in the system. **Endpoint:** `POST /api/v1/actions` **Request Body:** ```json { "ref": "core.http.get", "pack_ref": "core", "label": "HTTP GET Request", "description": "Performs an HTTP GET request to a specified URL", "entrypoint": "/actions/http_get.py", "runtime": 1, "param_schema": { "type": "object", "properties": { "url": { "type": "string" }, "headers": { "type": "object" } }, "required": ["url"] }, "out_schema": { "type": "object", "properties": { "status_code": { "type": "integer" }, "body": { "type": "string" } } } } ``` **Required Fields:** - `ref`: Unique reference identifier (alphanumeric, dots, underscores, hyphens) - `pack_ref`: Reference to the parent pack - `label`: Human-readable name (1-255 characters) - `description`: Action description (min 1 character) - `entrypoint`: Execution entry point (1-1024 characters) **Optional Fields:** - `runtime`: Runtime ID for execution environment - `param_schema`: JSON Schema defining input parameters - `out_schema`: JSON Schema defining expected outputs **Response:** `201 Created` ```json { "data": { "id": 1, "ref": "core.http.get", "pack": 1, "pack_ref": "core", "label": "HTTP GET Request", "description": "Performs an HTTP GET request to a specified URL", "entrypoint": "/actions/http_get.py", "runtime": 1, "param_schema": { ... }, "out_schema": { ... }, "created": "2024-01-13T10:00:00Z", "updated": "2024-01-13T10:00:00Z" }, "message": "Action created successfully" } ``` **Errors:** - `400 Bad Request`: Invalid request data or validation failure - `404 Not Found`: Referenced pack does not exist - `409 Conflict`: Action with the same ref already exists --- ### Update Action Update an existing action's properties. **Endpoint:** `PUT /api/v1/actions/:ref` **Path Parameters:** - `ref` (string): Action reference identifier **Request Body:** All fields are optional. Only provided fields will be updated. ```json { "label": "Updated HTTP GET Request", "description": "Updated description", "entrypoint": "/actions/http_get_v2.py", "runtime": 2, "param_schema": { ... }, "out_schema": { ... } } ``` **Response:** `200 OK` ```json { "data": { "id": 1, "ref": "core.http.get", "pack": 1, "pack_ref": "core", "label": "Updated HTTP GET Request", "description": "Updated description", "entrypoint": "/actions/http_get_v2.py", "runtime": 2, "param_schema": { ... }, "out_schema": { ... }, "created": "2024-01-13T10:00:00Z", "updated": "2024-01-13T12:00:00Z" }, "message": "Action updated successfully" } ``` **Errors:** - `400 Bad Request`: Invalid request data or validation failure - `404 Not Found`: Action with the specified ref does not exist --- ### Delete Action Delete an action from the system. **Endpoint:** `DELETE /api/v1/actions/:ref` **Path Parameters:** - `ref` (string): Action reference identifier **Response:** `200 OK` ```json { "success": true, "message": "Action 'core.http.get' deleted successfully" } ``` **Errors:** - `404 Not Found`: Action with the specified ref does not exist --- ### Get Queue Statistics Retrieve real-time queue statistics for an action's execution queue. **Endpoint:** `GET /api/v1/actions/:ref/queue-stats` **Path Parameters:** - `ref` (string): Action reference identifier **Response:** `200 OK` ```json { "data": { "action_id": 1, "action_ref": "core.http.get", "queue_length": 5, "active_count": 2, "max_concurrent": 3, "oldest_enqueued_at": "2025-01-27T10:30:00Z", "total_enqueued": 1250, "total_completed": 1245, "last_updated": "2025-01-27T12:45:30Z" } } ``` **Response Fields:** - `action_id`: Numeric action ID - `action_ref`: Action reference identifier - `queue_length`: Number of executions waiting in queue - `active_count`: Number of currently running executions - `max_concurrent`: Maximum concurrent executions allowed (from policy) - `oldest_enqueued_at`: Timestamp of oldest queued execution (null if queue empty) - `total_enqueued`: Lifetime count of executions enqueued - `total_completed`: Lifetime count of executions completed - `last_updated`: Last time statistics were updated **Response When No Queue Stats Available:** `200 OK` ```json { "data": { "action_id": 1, "action_ref": "core.http.get", "queue_length": 0, "active_count": 0, "max_concurrent": null, "oldest_enqueued_at": null, "total_enqueued": 0, "total_completed": 0, "last_updated": null } } ``` **Errors:** - `404 Not Found`: Action with the specified ref does not exist **Use Cases:** - Monitor action execution queue depth - Detect stuck or growing queues - Track execution throughput - Validate policy enforcement - Operational dashboards **Related Documentation:** - [Queue Architecture](./queue-architecture.md) - [Policy Enforcement](./executor-service.md#policy-enforcement) --- ## Examples ### Creating a Simple Action ```bash curl -X POST http://localhost:3000/api/v1/actions \ -H "Content-Type: application/json" \ -d '{ "ref": "mypack.hello_world", "pack_ref": "mypack", "label": "Hello World", "description": "Prints hello world", "entrypoint": "/actions/hello.py" }' ``` ### Creating an Action with Parameter Schema ```bash curl -X POST http://localhost:3000/api/v1/actions \ -H "Content-Type: application/json" \ -d '{ "ref": "mypack.send_email", "pack_ref": "mypack", "label": "Send Email", "description": "Sends an email message", "entrypoint": "/actions/send_email.py", "param_schema": { "type": "object", "properties": { "to": { "type": "string", "format": "email" }, "subject": { "type": "string" }, "body": { "type": "string" } }, "required": ["to", "subject", "body"] } }' ``` ### Listing Actions for a Pack ```bash curl http://localhost:3000/api/v1/packs/core/actions ``` ### Updating an Action ```bash curl -X PUT http://localhost:3000/api/v1/actions/mypack.hello_world \ -H "Content-Type: application/json" \ -d '{ "label": "Hello World v2", "description": "Updated hello world action" }' ``` ### Deleting an Action ```bash curl -X DELETE http://localhost:3000/api/v1/actions/mypack.hello_world ``` ### Getting Queue Statistics ```bash curl http://localhost:3000/api/v1/actions/core.http.get/queue-stats ``` **Example Response:** ```json { "data": { "action_id": 1, "action_ref": "core.http.get", "queue_length": 12, "active_count": 5, "max_concurrent": 5, "oldest_enqueued_at": "2025-01-27T12:40:00Z", "total_enqueued": 523, "total_completed": 511, "last_updated": "2025-01-27T12:45:30Z" } } ``` --- ## Validation Rules ### Action Reference (`ref`) - Must be unique across all actions - Can contain alphanumeric characters, dots (.), underscores (_), and hyphens (-) - Typically follows the pattern: `pack_name.action_name` - Example: `core.http.get`, `aws.ec2.start_instance` ### Pack Reference (`pack_ref`) - Must reference an existing pack - The pack must exist before creating actions for it ### Entry Point (`entrypoint`) - Path or identifier for the executable code - Can be a file path, module name, function name, etc. - Format depends on the runtime environment ### Schemas (`param_schema`, `out_schema`) - Must be valid JSON Schema documents - Used for validation during action execution - Helps with auto-generating documentation and UI --- ## Best Practices 1. **Naming Conventions** - Use descriptive, hierarchical names: `pack.category.action` - Keep names concise but meaningful - Use lowercase with dots as separators 2. **Schema Definitions** - Always provide `param_schema` for clarity - Define `required` fields in schemas - Use appropriate JSON Schema types and formats - Document schema fields with descriptions 3. **Entry Points** - Use consistent paths relative to the pack root - Keep entry points simple and maintainable - Consider versioning: `/actions/v1/http_get.py` 4. **Runtime Association** - Specify runtime when actions have specific dependencies - Null runtime means use default/generic runtime - Ensure runtime exists before creating action 5. **Error Handling** - Design actions to handle errors gracefully - Use output schemas to define error structures - Log execution details for debugging 6. **Queue Monitoring** - Use `/queue-stats` endpoint to monitor execution queues - Alert on high `queue_length` (> 100) - Investigate when `oldest_enqueued_at` is old (> 30 minutes) - Track completion rate: `total_completed / total_enqueued` --- ## Queue Statistics The `/queue-stats` endpoint provides real-time visibility into action execution queues. ### Understanding Queue Metrics - **queue_length**: Executions waiting to run (0 = healthy) - **active_count**: Executions currently running - **max_concurrent**: Policy-enforced concurrency limit - **oldest_enqueued_at**: How long the oldest execution has been waiting - **total_enqueued/completed**: Lifetime throughput metrics ### Healthy vs Unhealthy Queues **Healthy:** - ✅ `queue_length` is 0 or low (< 10) - ✅ `active_count` ≈ `max_concurrent` during load - ✅ `oldest_enqueued_at` is recent (< 5 minutes) - ✅ `total_completed` increases steadily **Unhealthy:** - ⚠️ `queue_length` consistently high (> 50) - ⚠️ `oldest_enqueued_at` is old (> 30 minutes) - 🚨 Queue not progressing (stats not updating) - 🚨 `active_count` < `max_concurrent` (workers stuck) ### Monitoring Recommendations 1. **Set up alerts** for high queue depths 2. **Track trends** in `total_enqueued` vs `total_completed` 3. **Investigate spikes** in `queue_length` 4. **Scale workers** when queues consistently fill 5. **Adjust policies** if concurrency limits are too restrictive For detailed queue architecture and troubleshooting, see [Queue Architecture Documentation](./queue-architecture.md). --- ## Related Documentation - [Pack Management API](./api-packs.md) - [Runtime Management API](./api-runtimes.md) - [Rule Management API](./api-rules.md) - [Execution API](./api-executions.md) - [Queue Architecture](./queue-architecture.md) - [Executor Service](./executor-service.md) --- **Last Updated:** January 27, 2025