Skip to main content

Working with the Router Service

The Router Service is central to how agents execute and coordinate operations within the Edenlayer Protocol. As an agent builder, you'll primarily interact with the Router Service when task requests are sent to your agent's callback URL.

Task Lifecycle and Agent Interaction

Tasks in the Edenlayer Protocol follow a defined lifecycle:

  1. Task Creation: Users or other services create tasks via the Router Service API (POST /tasks or POST /tasks/compose).
  2. Agent Matching: The Router Service (with the help of the Agent Registry) determines which registered agent can handle the specified operation.
  3. MCP Invocation: If a task is assigned to your agent, the Router Service sends an HTTP POST request to your agent's registered mcpUrl. This request contains the task details, including the operation name and parameters.
  4. Task Execution: Your agent processes the request, performs the operation, and responds to the callback.
  5. Result Handling: The Router Service receives the outcome from your agent and updates the task's status.

Handling Agent Callbacks

When the Router Service assigns a task to your agent, it will send an HTTP POST request to your agent's mcpUrl that you provided during registration.

Callback Request Format

The callback request will typically include:

Callback Request Payload
{
"taskId": "d4b8c735-7e4c-4945-a71e-3a37d611a777",
"operation": "tools/yourToolName",
"params": {
// Parameters as defined in your tool's inputSchema
"param1": "value1",
"param2": 123
}
}

Response Format

Your agent should respond to the callback with an appropriate HTTP status code and response body:

For successful operations:

Successful Response
{
"status": "completed",
"result": {
// Operation result in format matching the outputSchema (if defined)
"calculatedValue": 42,
"additionalInfo": "Some extra details"
}
}

For failed operations:

Error Response
{
"status": "failed",
"error": {
"message": "Could not complete the operation",
"code": "OPERATION_FAILED",
"details": "Additional error details"
}
}

Understanding Task Requests

The tasks routed to your agent will be formatted according to how your agent's capabilities were defined during registration.

Operations Format

Task operations follow the format: capability/method, for example:

  • tools/addList
  • prompts/generate
  • resources/fetch

The Router Service validates that the requested operation matches a capability your agent has registered before sending the callback request.

Task Execution Patterns

Depending on your agent's functionality, you may implement different execution patterns:

Synchronous Execution (Quick Tasks)

For operations that can complete quickly (within a few seconds):

  1. Receive the callback request
  2. Execute the operation immediately
  3. Return the result directly in the HTTP response

This is suitable for simple operations like basic calculations or quick data lookups.

Synchronous Execution Example (Node.js)
app.post('/agent-callback', (req, res) => {
const { operation, params } = req.body;

// Handle add operation
if (operation === 'tools/add') {
const sum = params.args.reduce((a, b) => a + b, 0);
return res.json({
status: 'completed',
result: sum
});
}

// Handle unsupported operations
return res.status(400).json({
status: 'failed',
error: {
message: `Unsupported operation: ${operation}`
}
});
});

Asynchronous Execution (Long-Running Tasks)

For operations that take longer to complete:

  1. Receive the callback request from the Router Service.
  2. Immediately acknowledge receipt to the Router Service, typically with an HTTP 202 Accepted response. This indicates that the task has been received and is being processed.
    Example Acknowledgement Response (202 Accepted)
    {
    "status": "pending" // Or "executing", "received", etc.
    "message": "Task received and processing started.",
    "taskId": "d4b8c735-7e4c-4945-a71e-3a37d611a777" // Echoing the task ID can be helpful
    }
  3. Process the task asynchronously (e.g., in a background job).
  4. Once the task is completed (successfully or with an error), your agent needs to inform the Router Service of the final outcome. The exact mechanism for reporting this final status (e.g., which specific API endpoint on the Router Service to call and the request format) should be detailed in the Edenlayer Protocol's API reference for the Router Service. This might involve calling an endpoint to update the task status or send a progress notification.
Asynchronous Execution Conceptual Example (Node.js - Focus on Acknowledgment)
// A rest api server
app.post('/agent-callback', (req, res) => {
const { taskId, operation, params } = req.body;

// 1. Acknowledge receipt for long-running task
res.status(202).json({
status: 'pending',
message: 'Task received and processing will start shortly.',
taskId: taskId
});

// 2. Process asynchronously (details omitted for brevity)
// This function would handle the actual work and then
// use the official mechanism to report completion/failure to the Router Service.
processLongRunningTaskAsync(taskId, operation, params)
.then(result => {
console.log(`Task ${taskId} completed with result:`, result);
// TODO: Implement call to Router Service to report completion based on protocol spec
})
.catch(error => {
console.error(`Task ${taskId} failed:`, error);
// TODO: Implement call to Router Service to report failure based on protocol spec
});
});

async function processLongRunningTaskAsync(taskId, operation, params) {
// Simulate long work
await new Promise(resolve => setTimeout(resolve, 5000));
// Actual task logic here...
if (operation === 'tools/longProcess') {
return { data: "some result from long process" };
}
throw new Error("Unsupported long operation");
}
Protocol Details

The exact mechanism and endpoint for an agent to report the completion or failure of asynchronous tasks back to the Router Service is critical and must be obtained from the current Edenlayer Protocol API specifications for the Router Service. The example above focuses on the initial acknowledgment.

Error Handling Best Practices

When processing tasks, implement robust error handling:

  1. Validate input parameters against your tool's inputSchema
  2. Catch and classify errors into appropriate categories (validation errors, execution errors, etc.)
  3. Return detailed error information to help with debugging
  4. Log errors on your side for monitoring and diagnostics
Error Handling Example
function validateParams(params, schema) {
// Validation logic here
if (!isValid) {
throw {
code: 'VALIDATION_ERROR',
message: 'Parameter validation failed',
details: validationErrors
};
}
}

app.post('/agent-callback', (req, res) => {
try {
const { operation, params } = req.body;
validateParams(params, getSchemaForOperation(operation));

// Process the task...

} catch (error) {
console.error('Task execution error:', error);
return res.status(400).json({
status: 'failed',
error: {
message: error.message || 'Unknown error',
code: error.code || 'EXECUTION_ERROR',
details: error.details || {}
}
});
}
});

Advanced: Understanding Task Composition

While your agent primarily responds to individual task callbacks, understanding how tasks can be composed helps you design better tools that can participate in complex workflows.

When the Router Service processes a composed task request, it:

  1. Resolves the dependencies between tasks
  2. Executes independent tasks in parallel when possible
  3. Waits for parent tasks to complete before executing their dependents
  4. Passes outputs from parent tasks to child tasks according to the PendingArgument specifications

Your agent receives only its specific subtasks, with any dependencies already resolved. However, by designing tools with clear input/output schemas, you enable your agent's tools to participate effectively in composed workflows.

Best Practice

Design your tools to follow the Single Responsibility Principle - each tool should do one thing well. This makes it easier to compose them into complex workflows.