Listen for tasks

Subscribing to tasks using the Lattice SDK

A taskable agent is an asset entity, or group of entities that can perform tasks.

An agent calls the following API to listen for tasks assigned to it in Lattice:

Before you begin

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

Integrate an agent

An asset is an entity under your control, or under the control of another operator or system. Assets may accept tasks such as search or tracking. An agent is an asset, or a group of assets, that can complete a specific set of defined tasks.

To publish an agent, do the following:

1

Define a TaskCatalog

The entity model’sTaskCatalog component defines the tasks that an asset can execute. An operator, using the Lattice UI or an a programmatic SDK integration, can use an entity override to modify the asset’s TaskCatalog.

For example, publish an asset with the following catalog to listen to, and execute VisualId, Monitor, and Investigate tasks assigned to it:

taskCatalog
1 "taskCatalog": {
2 // Define the tasks the asset can perform.
3 "taskDefinitions": [
4 {
5 // Set the task specification URL.
6 "taskSpecificationUrl": "type.googleapis.com/anduril.tasks.v2.VisualId",
7 },
8 {
9 // Set the task specification URL.
10 "taskSpecificationUrl": "type.googleapis.com/anduril.tasks.v2.Monitor",
11 },
12 {
13 // Set the task specification URL.
14 "taskSpecificationUrl": "type.googleapis.com/anduril.tasks.v2.Investigate",
15 },
16
17 ],
18 }
2

Publish the agent

Use the PublishEntity method to publish a taskable agent:

1package main
2
3import (
4 "context"
5 "fmt"
6 "net/http"
7 "os"
8 "time"
9
10 Lattice "github.com/anduril/lattice-sdk-go/v2"
11 "github.com/anduril/lattice-sdk-go/v2/client"
12 "github.com/anduril/lattice-sdk-go/v2/option"
13 "github.com/google/uuid"
14)
15
16func main() {
17 // Get environment variables
18 latticeEndpoint := os.Getenv("LATTICE_ENDPOINT")
19 environmentToken := os.Getenv("ENVIRONMENT_TOKEN")
20
21 // Remove sandboxesToken from the following statements if you are not developing on Sandboxes
22 sandboxesToken := os.Getenv("SANDBOXES_TOKEN")
23
24 // Check required environment variables
25 if latticeEndpoint == "" || environmentToken == "" || sandboxesToken == "" {
26 fmt.Println("Missing required environment variables")
27 os.Exit(1)
28 }
29
30 // Initialize headers for sandbox authorization
31 headers := http.Header{}
32 headers.Add("Anduril-Sandbox-Authorization", fmt.Sprintf("Bearer %s", sandboxesToken))
33
34 // Create the client
35 LatticeClient := client.NewClient(
36 option.WithToken(environmentToken),
37 option.WithBaseURL(fmt.Sprintf("https://%s", latticeEndpoint)),
38 option.WithHTTPHeader(headers),
39 )
40
41 // Generate a unique ID for the entity
42 entityId := uuid.New().String()
43
44 // Get creation time
45 creationTime := time.Now().UTC()
46
47 // Continuously publish the entity
48 for {
49 latestTimestamp := time.Now().UTC()
50 ctx := context.Background()
51
52 // Create entity to publish
53 entity := Lattice.Entity{
54 EntityID: &entityId,
55 Description: Lattice.String("Friendly drone asset"),
56 Aliases: &Lattice.Aliases{
57 Name: Lattice.String("Drone 1"),
58 },
59 IsLive: Lattice.Bool(true),
60 CreatedTime: Lattice.Time(creationTime),
61 ExpiryTime: Lattice.Time(creationTime.Add(1 * time.Minute)),
62 Ontology: &Lattice.Ontology{
63 Template: Lattice.OntologyTemplateTemplateAsset.Ptr(),
64 PlatformType: Lattice.String("UAV"),
65 },
66 MilView: &Lattice.MilView{
67 Disposition: Lattice.MilViewDispositionDispositionFriendly.Ptr(),
68 Environment: Lattice.MilViewEnvironmentEnvironmentAir.Ptr(),
69 },
70 Location: &Lattice.Location{
71 Position: &Lattice.Position{
72 LatitudeDegrees: Lattice.Float64(50.91402185768586),
73 LongitudeDegrees: Lattice.Float64(0.79203612077257),
74 AltitudeAsfMeters: Lattice.Float64(1000),
75 },
76 },
77 Provenance: &Lattice.Provenance{
78 IntegrationName: Lattice.String("your_integration_name"),
79 DataType: Lattice.String("your_data_type"),
80 SourceUpdateTime: Lattice.Time(latestTimestamp),
81 },
82 Health: &Lattice.Health{
83 ConnectionStatus: Lattice.HealthConnectionStatusConnectionStatusOnline.Ptr(),
84 HealthStatus: Lattice.HealthHealthStatusHealthStatusHealthy.Ptr(),
85 UpdateTime: Lattice.Time(latestTimestamp),
86 },
87 TaskCatalog: &Lattice.TaskCatalog{
88 TaskDefinitions: []*Lattice.TaskDefinition{
89 {TaskSpecificationURL: Lattice.String("type.googleapis.com/anduril.tasks.v2.VisualId")},
90 {TaskSpecificationURL: Lattice.String("type.googleapis.com/anduril.tasks.v2.Monitor")},
91 {TaskSpecificationURL: Lattice.String("type.googleapis.com/anduril.tasks.v2.Investigate")},
92 },
93 },
94 }
95
96 // Publish the entity
97 _, err := LatticeClient.Entities.PublishEntity(ctx, &entity)
98
99 // Handle errors
100 if err != nil {
101 fmt.Printf("Error publishing entity: %v\n", err)
102 } else {
103 fmt.Println("Published asset: " + entityId)
104 }
105
106 // Wait before next request
107 time.Sleep(5 * time.Second)
108 }
109}

If successful, you see the entity ID in the console. Copy the ID:

$2025-07-16T02:50:04.694Z [INFO]: Published asset: <entity-id>
3

Listen for tasks

Use the ListenAsAgent operation and replace AGENT_ID with the ID of the agent you just published. This lets the agent subscribe to, and listen for, tasks routed to it by Lattice:

1package main
2
3import (
4 "context"
5 "fmt"
6 "net/http"
7 "os"
8
9 Lattice "github.com/anduril/lattice-sdk-go/v2"
10 "github.com/anduril/lattice-sdk-go/v2/client"
11 "github.com/anduril/lattice-sdk-go/v2/option"
12)
13
14func main() {
15 // Get environment variables
16 latticeEndpoint := os.Getenv("LATTICE_ENDPOINT")
17 environmentToken := os.Getenv("ENVIRONMENT_TOKEN")
18
19 // Remove sandboxesToken from the following statements if you are not developing on Sandboxes
20 sandboxesToken := os.Getenv("SANDBOXES_TOKEN")
21
22 // Check required environment variables
23 if latticeEndpoint == "" || environmentToken == "" || sandboxesToken == "" {
24 fmt.Println("Missing required environment variables")
25 os.Exit(1)
26 }
27
28 // Initialize headers for sandbox authorization
29 headers := http.Header{}
30 headers.Add("Anduril-Sandbox-Authorization", fmt.Sprintf("Bearer %s", sandboxesToken))
31
32 // Create the client
33 LatticeClient := client.NewClient(
34 option.WithToken(environmentToken),
35 option.WithBaseURL(fmt.Sprintf("https://%s", latticeEndpoint)),
36 option.WithHTTPHeader(headers),
37 )
38
39 // Entity ID to listen for tasks
40 entityId := "Demo-Sim-Asset1"
41 fmt.Printf("Listening for tasks for entity %s...\n", entityId)
42
43 // Create context for the request
44 ctx := context.Background()
45
46 // Create agent selector
47 agentSelector := Lattice.AgentListener{
48 AgentSelector: &Lattice.EntityIDsSelector{
49 EntityIDs: []string{entityId},
50 },
51 }
52
53 // Listen for tasks
54 response, err := LatticeClient.Tasks.ListenAsAgent(ctx, &agentSelector)
55
56 // Handle errors
57 if err != nil {
58 fmt.Printf("Error listening for tasks: %v\n", err)
59 os.Exit(1)
60 }
61
62 // Check response type
63 if response.ExecuteRequest != nil {
64 fmt.Printf("Starting task: %s\n", *response.ExecuteRequest.Task.Description)
65 } else if response.CompleteRequest != nil {
66 fmt.Printf("Completing task: %s\n", *response.CompleteRequest.TaskID)
67 } else if response.CancelRequest != nil {
68 fmt.Printf("Cancelling task: %s\n", *response.CancelRequest.TaskID)
69 }
70}

If successful, you see the following output:

$Listening for tasks for entity with ID <entity-id>...
4

Assign a task using the Lattice UI

To assign a task, do the following:

  1. Open your environment’s Lattice UI, and choose the entity you published from the Assets panel on the left hand side.
  2. From the entity pane, choose Task, then select a task, for example, Follow. Each displayed task in the drop down corresponds with a TaskDefinition item in the agent’s TaskCatalog component:
    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 from the Targets drop down, then choose Execute Task:
    Shows the drop down menu where you can see available targets for the task.
5

Verify the response

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

$Received the following task: "Maintain sensor awareness on specified group or object."

Endpoints for operators

The operator should use the following endpoints from Lattice UI or a third-party UI:

  • CreateTask: Creates a new task. Lattice calls the CreateTask endpoint after a task’s details have been populated in the UI, and an operator presses “Execute Task” for the first time.
  • GetTask: Fetches the state of an existing task.
  • QueryTasks: Finds tasks that match the specified criteria.

What’s next