Task Runner
Managing asynchronous operations and concurrency.
Daydreams agents often need to perform asynchronous operations, primarily when
executing Actions that interact with external APIs, blockchains, or
other time-consuming processes. The framework includes a TaskRunner
to manage
these operations efficiently.
Purpose
The TaskRunner
serves two main purposes:
- Concurrency Control: It limits the number of asynchronous tasks (like action handlers) that run simultaneously. This prevents the agent from overwhelming external services with too many requests at once (rate limiting) or consuming excessive local resources.
- Prioritization (Future): While the core framework primarily uses default priority, the underlying queue supports prioritizing tasks, allowing more critical operations to potentially execute sooner.
Initialization and Configuration
A TaskRunner
instance is automatically created within createDreams
unless a
custom one is provided in the Config
. Its concurrency limit can be configured:
The concurrency limit determines how many tasks from the internal queue can be actively running at any given moment.
Internal Usage (runAction
)
The most common use of the TaskRunner
is internal to the framework. When the
agent parses an <action_call>
from the LLM (see
Streaming & Parsing), the handleActionCall
function
doesn't execute the action's handler directly. Instead, it uses
taskRunner.enqueueTask
to schedule the execution:
This ensures that action executions respect the concurrency limits set for the agent.
Defining Tasks (task
helper)
The framework uses a task
helper function (from @daydreamsai/core/task
) to
define named, reusable asynchronous operations that can be managed by the
TaskRunner
. Key framework tasks like runAction
(executing action handlers)
and runGenerate
(calling the LLM) are defined using this helper.
The TaskContext
passed to the task function includes:
callId
: A unique ID generated for this specific task execution.debug
: ADebugger
function instance (configured viaTaskOptions
or defaulting from agent config).
While you typically won't need to define new tasks often (most work happens in
action handlers), understanding this pattern helps clarify how core operations
like runAction
are structured and managed.
Direct Usage
While primarily used internally for actions, you could access the TaskRunner
via agent.taskRunner
within your custom code (e.g., inside an action handler
or context hook) if you need to manage additional complex, long-running, or
resource-intensive asynchronous operations with concurrency control. However,
simple async/await
within action handlers is usually sufficient.
The TaskRunner
provides robust management for the asynchronous operations
essential to the agent's functioning, ensuring stability and controlled resource
usage.