Skip to content
Follow one Task from submission to outcome
Public Preview

Task lifecycle: submission, outcomes, and continuations

Explains how the SDK submits Tasks, observes their completed, failed, or stopped outcomes, and creates continuation Tasks.

This page covers Task lifecycle, outcome observation, connection architecture, routing preferences, streaming, continuations, and responsibility boundaries.

  • Task submission, outcome observation, and Stop requests.
  • Outbound connection architecture and identity resolution.
  • RoutingPolicy preferences for route selection.
  • Streaming chunks and continuation Task behavior.
  • Responsibility split between Duale AI and your application.

Summaries were generated by AI.

The SDK submits Tasks and returns an AgentResponse handle for each one. Duale AI ends every accepted Task with one outcome: completed, failed, or stopped. A lost connection can hide that outcome from your application without changing it.

Agent harness defines Task, Tool Call, Tool Result, Task Outcome, and Continuation Task.

Follow one Task from submission to outcome

One Task from submission to outcomeYour application submits a Task with ask and keeps its Task identifier. The SDK sends the request over a connection your process opens, and Duale AI streams events back on it. When the model needs one of your SDK Tools, the request arrives on that stream, your function runs in your process, and the SDK returns the Tool Result. The Task ends with one outcome: completed, failed, or stopped. Awaiting model returns the validated result or raises the matching error. A Stop request is accepted at once, and only the outcome confirms that it took effect.

Observe the Task outcome

ask() returns an AgentResponse handle after the SDK’s circuit breaker allows the submission. The handle alone does not confirm that Duale AI accepted the request.

  • Save response.task_id before waiting for the result. The identifier is available immediately; it names a Task only if Duale AI accepts the submission. A Task identifier names a Task within its Tenant and Agent Identity; task_id states what a repeated identifier does.
  • await response.model() returns the validated Task Result for a completed outcome. It raises TaskStoppedError for a stopped outcome, DualeAIError for a failed outcome, or ValidationError when a completed result misses the requested schema. If the connection cannot recover, observation can end with another exception instead.

A completed Task has a final answer that satisfies its requested response format or schema. Tool Calls are part of the work; they do not replace the final answer. The outcome has no partial-success state or completeness flag.

Every Task has an absolute deadline; ask states the default. Deadlines and Stop explains what happens near the deadline. Troubleshoot the SDK covers each exception and its recovery.

Cancelling response.task ends local submission and observation. It neither sends a Stop nor confirms acceptance. To request a Stop, call await response.stop(reason) and keep observing the outcome. Stop the Task you intend to stop states what a Stop covers.

Your process opens every connection

One outbound HTTPS stream carries a Task’s events and the Tool Calls for your SDK Tools. Tool Results, Tool Host publication, and credential renewal use further outbound requests. Duale AI opens no inbound connection to your process, so the host needs outbound HTTPS but no public address.

The token decides the Tenant and Agent Identity of every request; identifiers in the payload cannot override them. See Identity for credentials and permissions.

SDK configuration lists every destination your egress policy must allow. Duale AI, not your process, reaches the model endpoints in your pool; Plan the deployment explains that separate network path.

Influence routing without selecting a provider

Pass a RoutingPolicy to express your preferences. Duale AI ranks the eligible routes in your pool and can try more than one before the Task reaches its final outcome:

from dualeai import RoutingPolicy

policy = RoutingPolicy(
    target_accuracy=0.9,
    cost_sensitivity=0.3,
    speed_preference=0.5,
    required_capabilities=["problem_solving"],
)

Every field is optional. required_capabilities is also a preference: Duale AI relaxes it when the pool cannot meet the full request. target_permissiveness influences route selection; it is not a safety control.

Routing contract and limits lists every field, range, and guarantee.

Stream the answer and order its chunks

Pass streaming=True and read response.stream() to show a free-text answer while Duale AI writes it. The streamed chunks are a live view for display: they can arrive out of order, and the final result from await response.model() replaces them. Stream an answer gives the ordering rule and a runnable example.

Continue a Task

Use response.next() to continue a Task while it runs or after any outcome: completed, failed, or stopped. It creates a new Task with its own identifier, deadline, result, and Stop. It needs the earlier AgentResponse; a Task identifier alone is not enough in the SDK. Two continuations can share a parent, but neither sees the other’s later work.

  • next() does not wait for the parent’s outcome and does not validate it. Await response.model() first if you need the parent’s validated result.
  • An omitted response format, streaming choice, or routing policy keeps the parent’s value. The continuation never inherits res=; pass it to .next() to choose the continuation’s validation type.
  • The continuation’s deadline is its own; the parent’s deadline does not bound it.
  • The continuation uses the Tools its Agent Identity can use when it runs, not the parent’s set.
  • It needs agent:continue_task and agent:read_task on the parent, and agent:read_task on the new Task (Task actions).

On a long Task, the model receives a shortened view of earlier messages and Tool Results, and the stored history stays unchanged. Context continuity states what history a continuation inherits, how long a Task can be continued, and how the model can look up earlier Tasks of the same Agent Identity.

Branch from a running Task shows how an application lets end users branch work from a Task that is still running.

Keep application controls in your code

Duale AI managesYour application owns
Eligible route selection and retriesTask instruction, response model, deadline, and preferences
Task state and its single final outcomePersisting the Task ID and observed outcome
SDK Tool Call delivery through the Task streamSDK Tool code, action authorization, and Effect reconciliation
MCP Connection checks and the current catalogRemote server, credential, assignment, and action authorization
Library processing, document status, and searchLibrary paths, uploads, tags, access decisions, and deletion
Tenant and Agent Identity resolution from the tokenToken secrecy and the business decision to accept a result
  • Duale AI manages
    Eligible route selection and retries
    Your application owns
    Task instruction, response model, deadline, and preferences
  • Duale AI manages
    Task state and its single final outcome
    Your application owns
    Persisting the Task ID and observed outcome
  • Duale AI manages
    SDK Tool Call delivery through the Task stream
    Your application owns
    SDK Tool code, action authorization, and Effect reconciliation
  • Duale AI manages
    MCP Connection checks and the current catalog
    Your application owns
    Remote server, credential, assignment, and action authorization
  • Duale AI manages
    Library processing, document status, and search
    Your application owns
    Library paths, uploads, tags, access decisions, and deletion
  • Duale AI manages
    Tenant and Agent Identity resolution from the token
    Your application owns
    Token secrecy and the business decision to accept a result

Secure integration covers authorization and external Effects for SDK and MCP Tools.