For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Logo
ContactLearn More
GuidesReferenceSamplesLicenseChangelog
GuidesReferenceSamplesLicenseChangelog
  • Concepts
    • Overview
    • Principles
  • Getting started
    • Set up
    • Authenticate
    • Quickstart
  • Best practices
    • Choose a protocol
    • Connect offline
    • Retry connections
  • Developer tools
    • Sandboxes
  • Entities
    • Overview
    • Watch
    • Publish
  • Tasks
    • Overview
    • Operate
    • Listen
    • Update
  • Objects
    • Overview
    • Upload
    • Download
    • Manage
ContactLearn More
On this page
  • Before you begin
  • Start performing a task
  • Update the status of a task
  • What’s next
Tasks

Update tasks

Updating the status of tasks in Lattice using the Lattice SDK
Previous

Objects overview

The objects model and how it lets you store and access files across Lattice
Next

In Lattice, a task status represents each stage of the task lifecycle. When an agent receives a task, it calls the following API to update a task in Lattice:

  • UpdateStatus: Used to report real-time status updates to Lattice as the agent makes progress through a task.

Before you begin

  • To publish taskable entities, and subscribe to tasks, set up your Lattice environment.
  • Familiarize yourself with entities and different entity types.
gRPC authentication

If you are using gRPC with client credentials, set up the token refresh module before running the examples on this page.

Start performing a task

After an agent has identified a task to perform and begins to make progress towards its objective, it communicates back to Lattice using the UpdateTaskStatus to cycle through various states of a task lifecycle.

To update the status of a task, do the following:

1

Stream tasks as an agent

Use the UpdateTaskStatus operation. In this example, the agent listens to a stream of assigned tasks, then updates the task status, incrementing the StatusVersion of the task.

Replace AGENT_ID with the ID of the agent you want to task. If you are developing on Sandboxes, replace this with the following simulated asset: Demo-Sim-Asset1:

1package main
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "io"
8 "log"
9 "net/http"
10 "os"
11 "time"
12
13 Lattice "github.com/anduril/lattice-sdk-go/v4"
14 "github.com/anduril/lattice-sdk-go/v4/client"
15 "github.com/anduril/lattice-sdk-go/v4/option"
16)
17
18func main() {
19 // Get environment variables
20 latticeEndpoint := os.Getenv("LATTICE_ENDPOINT")
21 clientSecret := os.Getenv("LATTICE_CLIENT_SECRET")
22 clientId := os.Getenv("LATTICE_CLIENT_ID")
23 sandboxesToken := os.Getenv("SANDBOXES_TOKEN")
24
25 // Check required environment variables
26 if latticeEndpoint == "" || clientId == "" || clientSecret == "" || sandboxesToken == "" {
27 fmt.Println("Missing required environment variables")
28 os.Exit(1)
29 }
30
31 // Initialize headers for sandbox authorization
32 headers := http.Header{}
33 headers.Add("Anduril-Sandbox-Authorization", fmt.Sprintf("Bearer %s", sandboxesToken))
34 // Create the client
35 LatticeClient := client.NewClient(
36 option.WithClientCredentials(clientId, clientSecret),
37 option.WithBaseURL(fmt.Sprintf("https://%s", latticeEndpoint)),
38 option.WithHTTPHeader(headers),
39 )
40
41 // Set the entity ID to listen for tasks
42 entityId := "<AGENT_ID>"
43 fmt.Printf("Streaming tasks for entity %s...\n", entityId)
44
45 // Create context for the request
46 ctx := context.Background()
47
48 // Create agent stream request
49 agentStreamRequest := Lattice.AgentStreamRequest{
50 AgentSelector: &Lattice.EntityIDsSelector{
51 EntityIDs: []string{entityId},
52 },
53 }
54
55 // Stream tasks
56 stream, err := LatticeClient.Tasks.StreamAsAgent(ctx, &agentStreamRequest)
57 if err != nil {
58 fmt.Printf("Error streaming tasks: %v\n", err)
59 os.Exit(1)
60 }
61
62 // Process stream events
63 for {
64 select {
65 case <-ctx.Done():
66 log.Printf("Context canceled: %v", ctx.Err())
67 return
68 default:
69 // Continue processing
70 }
71
72 event, err := stream.Recv()
73
74 if errors.Is(err, io.EOF) {
75 log.Println("Stream completed successfully.")
76 return
77 }
78
79 if err != nil {
80 log.Printf("Error receiving message: %v", err)
81 continue
82 }
83
84 if event.Event == "heartbeat" {
85 timestamp := *event.Heartbeat.Timestamp
86 log.Printf("Heartbeat: %s", timestamp)
87 } else {
88 request := event.GetAgentRequest()
89 if executeRequest := request.GetExecuteRequest(); executeRequest != nil {
90 task := executeRequest.GetTask()
91 if task != nil {
92 taskId := *task.GetVersion().GetTaskID()
93 taskStatusVersion := *task.GetVersion().GetStatusVersion()
94 description := *task.GetDescription()
95
96 log.Printf("Starting task %s, version %d: %s", taskId, taskStatusVersion, description)
97
98 // Update task status to STATUS_EXECUTING
99 result, err := startTask(ctx, LatticeClient, taskId, int(taskStatusVersion), entityId)
100 if err != nil {
101 log.Printf("Error starting task: %v", err)
102 continue
103 }
104
105 log.Printf("Started task with status version: %d", *result.StatusVersion)
106 }
107 } else if completeRequest := request.GetCompleteRequest(); completeRequest != nil {
108 taskToComplete := completeRequest.GetTaskID()
109 if taskToComplete != nil {
110 log.Printf("Completing task: %s", *taskToComplete)
111 }
112 } else if cancelRequest := request.GetCancelRequest(); cancelRequest != nil {
113 taskToCancel := cancelRequest.GetTaskID()
114 if taskToCancel != nil {
115 log.Printf("Cancelling task: %s", *taskToCancel)
116 }
117 }
118 }
119
120 // Sleep briefly to prevent tight looping
121 time.Sleep(100 * time.Millisecond)
122 }
123}
124
125// startTask updates the task status to STATUS_EXECUTING
126func startTask(ctx context.Context, client *client.Client, taskId string, taskStatusVersion int, agentEntityId string) (*Lattice.TaskVersion, error) {
127 // Increment status version for the update
128 taskStatusVersion++
129
130 // Create system principal with the agent entity ID
131 principal := Lattice.Principal{
132 System: &Lattice.System{
133 EntityID: &agentEntityId,
134 },
135 }
136
137 taskStatus := Lattice.TaskStatus{
138 Status: Lattice.TaskStatusStatusStatusExecuting.Ptr(),
139 }
140
141 // Create task status update request
142 taskStatusUpdate := Lattice.TaskStatusUpdate{
143 TaskID: taskId,
144 StatusVersion: &taskStatusVersion,
145 NewStatus: &taskStatus,
146 Author: &principal,
147 }
148
149 // Call the UpdateTaskStatus API
150 task, err := client.Tasks.UpdateTaskStatus(ctx, &taskStatusUpdate)
151 if err != nil {
152 return nil, fmt.Errorf("error updating task status: %w", err)
153 }
154
155 return task.Version, nil
156}
2

Assign a task using the UI

To assign a task, do the following:

  1. Open your environment’s Lattice UI, and choose an asset from the Assets panel. On Sandboxes, choose Demo-Sim-Asset1:
  2. From the entity pane, choose Task, then select a task, for example, Follow:
    Shows the drop down menu where you can see the available tasks for the entity.
  3. From the Task Details panel on the right hand side, select a target then choose Execute Task:
    Shows the drop down menu where you can see available targets for the task.
3

Verify the task status

If successful, you see the following output in your local development console:

$Starting task <task-id>, version 1.
$Started task with status version: 2.

The agent has successfully updated the tasks status and incremented the task status version.

Update the status of a task

In Lattice tasks move through the following states:

1

STATUS_SENT

The agent receives a task with STATUS_SENT:

1"task": {
2 "version": {
3 "taskId": "my-task",
4 "definitionVersion": 1,
5 "statusVersion": 1
6 },
7 "status": {
8 "status": "STATUS_SENT"
9 }
10}
2

STATUS_MACHINE_RECEIPT

The agent then responds back with status STATUS_MACHINE_RECEIPT, indicating that the task has been received, and incrementing statusVersion accordingly:

1"statusUpdate": {
2 "version": {
3 "taskId": "my-task",
4 "definitionVersion": 1,
5 "statusVersion": 2
6 },
7 "status": {
8 "status": "STATUS_MACHINE_RECEIPT"
9 }
10}
3

STATUS_ACK

When the agent is ready to acknowledge the task, it does so using STATUS_ACK, and again increments statusVersion:

1"statusUpdate": {
2 "version": {
3 "taskId": "my-task",
4 "definitionVersion": 1,
5 "statusVersion": 3
6 },
7 "status": {
8 "status": "STATUS_ACK"
9 }
10}
4

STATUS_WILCO

The agent confirms it intends to execute the task using STATUS_WILCO:

1"statusUpdate": {
2 "version": {
3 "taskId": "my-task",
4 "definitionVersion": 1,
5 "statusVersion": 4
6 },
7 "status": {
8 "status": "STATUS_WILCO"
9 }
10}
5

STATUS_EXECUTING

As the agent begins to actively execute the task, it indicates this by reporting STATUS_EXECUTING back to Lattice:

1"statusUpdate": {
2 "version": {
3 "taskId": "my-task",
4 "definitionVersion": 1,
5 "statusVersion": 5
6 },
7 "status": {
8 "status": "STATUS_EXECUTING"
9 }
10}
6

STATUS_DONE_OK

Finally, when the agent reaches a terminal state and completes the task successfully, it reports STATUS_DONE_OK. This might result from operator-initiated requests for task completion:

1"statusUpdate": {
2 "version": {
3 "taskId": "my-task",
4 "definitionVersion": 1,
5 "statusVersion": 6
6 },
7 "status": {
8 "status": "STATUS_DONE_OK"
9 }
10}
7

STATUS_DONE_NOT_OK

If the agent reaches a terminal state but does not complete the task successfully, it reports STATUS_DONE_NOT_OK. This might result from operator-initiated requests for task completion or cancellation. The agent should include a descriptive TaskError when reporting STATUS_DONE_NOT_OK:

1"statusUpdate": {
2 "version": {
3 "taskId": "my-task",
4 "definitionVersion": 1,
5 "statusVersion": 7
6 },
7 "status": {
8 "status": "DONE_NOT_OK",
9 "taskError": {
10 "code": "ERROR_CODE_FAILED",
11 "message": "The asset failed task execution due to an internal error.",
12 }
13 }
14}

In this example, the message indicates that the agent encountered an internal error during task execution. You can add more descriptive errors to help the operator troubleshoot the issue accordingly.

The STATUS_DONE_OK and STATUS_DONE_NOT_OK statuses are considered terminal states. Once a task’s reaches either state, it’s complete and cannot be updated.

What’s next

  • To learn more about tasks, see Task an asset in in the Lattice SDK sample applications guide.