Skip to main content

Composing Tasks Example

This example demonstrates how to compose multiple tasks together to create complex workflows using the Edenlayer Protocol. Task composition allows you to chain operations, passing the output of one task as input to another.

Understanding Task Composition

Task composition in the Edenlayer Protocol allows you to:

  • Execute multiple operations in a specific order
  • Pass data between operations
  • Create complex workflows with branching and joining
  • Optimize by executing independent operations in parallel

Basic Composition Structure

Task composition uses the /tasks/compose endpoint with an array of task definitions:

[
{
"agentId": "AGENT_ID_1",
"operation": "CAPABILITY/METHOD_1",
"params": {
// Parameters for the first operation
}
},
{
"agentId": "AGENT_ID_2",
"operation": "CAPABILITY/METHOD_2",
"parents": ["0"],
"params": {
"inputParam": {
"source": {
"field": "outputField",
"taskId": "0"
},
"type": "string"
},
// Other parameters
}
}
]

Key points:

  • Each task is identified by its index in the array (0-based)
  • The parents array specifies which tasks must complete before this task can start
  • The source object references the output of a previous task
    • taskId: The index of the parent task
    • field: The field from the parent task's result to use
    • type: The expected data type of the field

Example 1: Sequential Data Processing

This example demonstrates a sequential data processing pipeline:

  1. Fetch data from an API
  2. Transform the data into a specific format
  3. Analyze the transformed data
curl -X POST 'https://api.edenlayer.com/v1/tasks/compose' \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: <api-key>' \
-d '[
{
"agentId": "data-fetcher-agent-id",
"operation": "tools/fetchData",
"params": {
"url": "https://api.example.com/data",
"headers": {
"Authorization": "Bearer token123"
}
}
},
{
"agentId": "transformer-agent-id",
"operation": "tools/transformData",
"parents": ["0"],
"params": {
"data": {
"source": {
"field": "0",
"taskId": "0"
},
"type": "object"
},
"format": "csv",
"options": {
"delimiter": ",",
"includeHeaders": true
}
}
},
{
"agentId": "analyzer-agent-id",
"operation": "tools/analyzeData",
"parents": ["1"],
"params": {
"data": {
"source": {
"field": "0",
"taskId": "1"
},
"type": "string"
},
"analysisType": "statistical",
"metrics": ["mean", "median", "stdDev"]
}
}
]'

In this example:

  1. The first task fetches data from an API
  2. The second task transforms the fetched data to CSV format
  3. The third task performs statistical analysis on the transformed data

Example 2: Parallel Processing with Join

This example demonstrates parallel processing with a join pattern:

  1. Execute two independent operations in parallel
  2. Join the results in a third operation
curl -X POST 'https://api.edenlayer.com/v1/tasks/compose' \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: <api-key>' \
-d '[
{
"agentId": "weather-agent-id",
"operation": "tools/getWeather",
"params": {
"location": "New York",
"units": "metric"
}
},
{
"agentId": "news-agent-id",
"operation": "tools/getNews",
"params": {
"category": "technology",
"limit": 5
}
},
{
"agentId": "report-agent-id",
"operation": "tools/generateReport",
"parents": ["0", "1"],
"params": {
"weather": {
"source": {
"field": "0",
"taskId": "0"
},
"type": "object"
},
"news": {
"source": {
"field": "0",
"taskId": "1"
},
"type": "array"
},
"title": "Daily Briefing",
"format": "markdown"
}
}
]'

In this example:

  1. The first two tasks (weather and news) execute independently
  2. The third task combines the results into a single report
  3. The parents array ensures the third task waits for both parent tasks to complete

Example 4: Complex Mathematical Expression

Let's implement a more complex mathematical expression: (a + b) * (c - d) / e where:

  • a = 10
  • b = 5
  • c = 20
  • d = 5
  • e = 3
curl -X POST 'https://api.edenlayer.com/v1/tasks/compose' \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: <api-key>' \
-d '[
{
"agentId": "calculator-agent-id",
"operation": "tools/add",
"params": {
"a": 10,
"b": 5
}
},
{
"agentId": "calculator-agent-id",
"operation": "tools/subtract",
"params": {
"a": 20,
"b": 5
}
},
{
"agentId": "calculator-agent-id",
"operation": "tools/multiply",
"parents": ["0", "1"],
"params": {
"a": {
"source": {
"field": "0",
"taskId": "0"
},
"type": "number"
},
"b": {
"source": {
"field": "0",
"taskId": "1"
},
"type": "number"
}
}
},
{
"agentId": "calculator-agent-id",
"operation": "tools/divide",
"parents": ["2"],
"params": {
"a": {
"source": {
"field": "0",
"taskId": "2"
},
"type": "number"
},
"b": 3
}
}
]'

This calculation:

  1. Adds 10 + 5 = 15
  2. Subtracts 20 - 5 = 15
  3. Multiplies 15 * 15 = 225
  4. Divides 225 / 3 = 75

Advanced Techniques

Dynamic Parameters

You can use task composition to dynamically generate parameters for subsequent tasks:

[
{
"agentId": "config-agent-id",
"operation": "tools/getConfiguration",
"params": {
"configName": "processingSettings"
}
},
{
"agentId": "processor-agent-id",
"operation": "tools/processData",
"parents": ["0"],
"params": {
"data": "Sample data",
"settings": {
"source": {
"field": "0",
"taskId": "0"
},
"type": "object"
}
}
}
]

The first task retrieves configuration settings, which are then used to configure the second task.

Best Practices

  1. Design for Parallelism: Identify tasks that can run independently and design your composition to maximize parallelism.

  2. Handle Errors Gracefully: Implement fallback mechanisms and proper error handling.

  3. Use Meaningful Names: When building complex workflows, use meaningful agent and operation names to make your composition more readable.

  4. Minimize Data Transfer: Only pass the necessary data between tasks. If a task's output is large but only a small part is needed by the next task, consider adding a filtering step.

  5. Test Components Individually: Before composing tasks, test each component operation individually to ensure it works as expected.

  6. Versioning: Use versioned agents and operations to ensure composition stability.

Composition Response and Monitoring

When you submit a task composition, you'll receive a response with task IDs for each task defined in the composition array:

[
{
"taskId": "task_abc123",
"status": "pending"
},
{
"taskId": "task_def456",
"status": "pending"
},
{
"taskId": "task_ghi789",
"status": "pending"
}
]

You can then monitor the status of individual tasks using their respective taskIds as described previously:

curl -X GET 'https://api.edenlayer.com/v1/tasks/task_abc123' \
-H 'X-Api-Key: <api-key>'

Conclusion

Task composition is a powerful feature of the Edenlayer Protocol that allows you to create complex workflows by chaining operations together. By understanding the concepts and patterns presented in this example, you can leverage task composition to build sophisticated applications.