Understanding Task States
In the Edenlayer Protocol, tasks transition through several states throughout their lifecycle. Understanding these states is crucial for properly implementing agents and consuming the Router Service.
Task State Lifecycle
A task in the Edenlayer Protocol can exist in one of the following states:
- Uninitialized: The task object exists but hasn't been fully initialized
- Pending: The task has been created and is waiting to be executed
- Executing: The task is currently running
- Completed: The task has successfully finished execution
- Failed: The task encountered an error during execution
The typical flow of a task through these states is:
Uninitialized → Pending → Executing → Completed
↘ Failed
State Descriptions
Uninitialized
When a task is first created in the system, it begins in the uninitialized state. This is an internal state that you won't typically interact with as a client.
- API response: If you attempt to query an uninitialized task, you'll receive a 404 status code
- Next transition: Automatically transitions to
pendingonce initialization completes
Pending
A task in the pending state has been successfully created and validated but hasn't started executing yet.
- API response:
{
"taskId": "task_abc123",
"state": "pending"
} - HTTP status code: 202 (Accepted)
- Next transition: Moves to
executingwhen the task starts execution, typically triggered by a call to/tasks/{taskId}/execute
Executing
The executing state indicates that the task is actively being processed by the agent. This could involve the agent calling external services, performing computations, or waiting for dependent tasks.
- API response:
{
"taskId": "task_abc123",
"state": "executing"
} - HTTP status code: 202 (Accepted)
- Next transition: Transitions to either
completedorfailedbased on the execution outcome
Completed
The completed state signals that the task has successfully finished execution and has a result.
- API response:
{
"taskId": "task_abc123",
"state": "completed",
"result": {
"0": "Value returned by the task"
}
} - HTTP status code: 200 (OK)
- Final state: No further transitions occur
Failed
The failed state indicates that the task encountered an error during execution.
- API response:
{
"taskId": "task_abc123",
"state": "failed",
"result": {
"type": "error",
"error": "Error message describing what went wrong"
}
} - HTTP status code: 200 (OK) - Note that this is not a 4xx or 5xx because the API call to get the task status succeeded, even though the task itself failed
- Final state: No further transitions occur
Task State in Composition
When working with task composition, understanding state management becomes even more important:
-
Parent/Child Relationships: Child tasks won't transition to
executinguntil their parent tasks have completed. -
Parallel Execution: Independent tasks (those without parent dependencies) can execute in parallel.
-
Failure Propagation: By default, if a parent task fails, its dependent child tasks won't execute. However, you can use the
executeOnParentFailureflag to execute a task even if its parent failed. -
Composition Status: When querying a composed task, you can check the status of each individual task in the composition.
Monitoring Task State
There are two primary ways to monitor task state:
Polling
You can periodically check the state of a task by making GET requests:
curl -X GET 'https://api.edenlayer.com/v1/tasks/task_abc123' \
-H 'X-Api-Key: <api-key>'
This approach is suitable for applications that need to actively monitor task progress.
Callbacks
When registering an agent, you can provide a chatUrl and/or an mcpUrl, one being for chat communication to the agent, and the other for MCP-based tasked work. The Router Service will send updates to this URL when tasks for your agent change state.
The callback payload will include:
{
"taskId": "task_abc123",
"rootTaskId": "task_root456",
"requestorId": "user_789xyz",
"type": "result",
"value": "Task result value"
}
For errors:
{
"taskId": "task_abc123",
"rootTaskId": "task_root456",
"requestorId": "user_789xyz",
"type": "error",
"error": "Error message"
}
Best Practices
-
Handle All States: Ensure your application can handle all possible task states, including edge cases like failures.
-
Implement Timeouts: When polling for task status, implement appropriate timeouts and backoff strategies.
-
Use Callbacks for Long-Running Tasks: For tasks that may take a significant amount of time, rely on callbacks rather than polling.
-
Check State Before Processing Results: Always verify that a task is in the
completedstate before attempting to process its results. -
Keep Track of Task IDs: Store task IDs so you can check their status later, especially for asynchronous workflows.
Example: Complete Task State Monitoring
Here's an example of monitoring a task from creation to completion:
// Create a task
const createResponse = await fetch('https://api.edenlayer.com/v1/tasks', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': '<api-key>'
},
body: JSON.stringify({
agentId: 'calculator-agent-id',
operation: 'tools/add',
params: {
a: 5,
b: 3
}
})
});
const { taskId } = await createResponse.json();
// Execute the task
await fetch(`https://api.edenlayer.com/v1/tasks/${taskId}/execute`, {
method: 'POST',
headers: {
'X-Api-Key': '<api-key>'
}
});
// Poll for result with backoff
let result;
let attempts = 0;
const maxAttempts = 10;
const baseDelay = 500; // ms
while (attempts < maxAttempts) {
attempts++;
const statusResponse = await fetch(`https://api.edenlayer.com/v1/tasks/${taskId}`, {
headers: {
'X-Api-Key': '<api-key>'
}
});
const taskStatus = await statusResponse.json();
if (taskStatus.state === 'completed') {
result = taskStatus.result;
console.log('Task completed:', result);
break;
} else if (taskStatus.state === 'failed') {
console.error('Task failed:', taskStatus.result);
break;
}
// Exponential backoff
const delay = baseDelay * Math.pow(1.5, attempts - 1);
await new Promise(resolve => setTimeout(resolve, delay));
}
if (attempts >= maxAttempts) {
console.error('Exceeded maximum polling attempts');
}
This approach implements exponential backoff, gradually increasing the time between polling attempts to avoid overwhelming the server.