diff --git a/.fern/metadata.json b/.fern/metadata.json index 7c8be267..2aba3afd 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -1,9 +1,10 @@ { - "cliVersion": "3.5.0", + "cliVersion": "3.37.6", "generatorName": "fernapi/fern-java-sdk", - "generatorVersion": "3.18.5", + "generatorVersion": "3.27.6", "generatorConfig": { "client-class-name": "Lattice", "package-prefix": "com.anduril" - } + }, + "sdkVersion": "5.1.0" } \ No newline at end of file diff --git a/README.md b/README.md index 482f4538..f7ad22ca 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Add the dependency in your `pom.xml` file: com.anduril lattice-sdk - 5.0.0 + 5.1.0 ``` @@ -72,10 +72,9 @@ import com.anduril.resources.entities.requests.EntityEventRequest; public class Example { public static void main(String[] args) { - Lattice client = Lattice - .builder() - .token("") - .build(); + Lattice client = Lattice.withCredentials("", "") + .build() + ; client.entities().longPollEntityEvents( EntityEventRequest @@ -86,6 +85,29 @@ public class Example { } } ``` +## Authentication + +This SDK supports two authentication methods: + +### Option 1: Direct Bearer Token + +If you already have a valid access token, you can use it directly: + +```java +Lattice client = Lattice.withToken("your-access-token") + .url("https://api.example.com") + .build(); +``` + +### Option 2: OAuth Client Credentials + +The SDK can automatically handle token acquisition and refresh: + +```java +Lattice client = Lattice.withCredentials("client-id", "client-secret") + .url("https://api.example.com") + .build(); +``` ## Environments @@ -175,7 +197,6 @@ Lattice client = Lattice ### Timeouts The SDK defaults to a 60 second timeout. You can configure this with a timeout option at the client or request level. - ```java import com.anduril.Lattice; import com.anduril.core.RequestOptions; @@ -183,7 +204,7 @@ import com.anduril.core.RequestOptions; // Client level Lattice client = Lattice .builder() - .timeout(10) + .timeout(60) .build(); // Request level @@ -191,7 +212,7 @@ client.entities().longPollEntityEvents( ..., RequestOptions .builder() - .timeout(10) + .timeout(60) .build() ); ``` diff --git a/build.gradle b/build.gradle index f7d7e49c..1081a6d4 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ java { group = 'com.anduril' -version = '5.0.0' +version = '5.1.0' jar { dependsOn(":generatePomFileForMavenPublication") @@ -78,21 +78,21 @@ publishing { maven(MavenPublication) { groupId = 'com.anduril' artifactId = 'lattice-sdk' - version = '5.0.0' + version = '5.1.0' from components.java pom { - name = 'Anduril Industries, Inc.' - description = 'Anduril Lattice SDK for Java' - url = 'https://developer.anduril.com' + name = 'anduril' + description = 'The official SDK of anduril' + url = 'https://buildwithfern.com' licenses { license { - name = 'Anduril Lattice Software Development Kit License Agreement' + name = 'Custom License (LICENSE)' } } developers { developer { - name = 'Anduril Industries, Inc.' - email = 'lattice-developers@anduril.com' + name = 'anduril' + email = 'developers@anduril.com' } } scm { diff --git a/reference.md b/reference.md new file mode 100644 index 00000000..e5581737 --- /dev/null +++ b/reference.md @@ -0,0 +1,1319 @@ +# Reference +## Entities +
client.entities.publishEntity(request) -> Entity +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Publish an entity for ingest into the Entities API. Entities created with this method are "owned" by the originator: other sources, +such as the UI, may not edit or delete these entities. The server validates entities at API call time and +returns an error if the entity is invalid. + +An entity ID must be provided when calling this endpoint. If the entity referenced by the entity ID does not exist +then it will be created. Otherwise the entity will be updated. An entity will only be updated if its +provenance.sourceUpdateTime is greater than the provenance.sourceUpdateTime of the existing entity. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.entities().publishEntity( + Entity + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Entity` + +
+
+
+
+ + +
+
+
+ +
client.entities.getEntity(entityId) -> Entity +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.entities().getEntity( + "entityId", + GetEntityRequest + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**entityId:** `String` — ID of the entity to return + +
+
+
+
+ + +
+
+
+ +
client.entities.overrideEntity(entityId, fieldPath, request) -> Entity +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Only fields marked with overridable can be overridden. Please refer to our documentation to see the comprehensive +list of fields that can be overridden. The entity in the request body should only have a value set on the field +specified in the field path parameter. Field paths are rooted in the base entity object and must be represented +using lower_snake_case. Do not include "entity" in the field path. + +Note that overrides are applied in an eventually consistent manner. If multiple overrides are created +concurrently for the same field path, the last writer wins. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.entities().overrideEntity( + "entityId", + "mil_view.disposition", + EntityOverride + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**entityId:** `String` — The unique ID of the entity to override + +
+
+ +
+
+ +**fieldPath:** `String` — fieldPath to override + +
+
+ +
+
+ +**entity:** `Optional` + +The entity containing the overridden fields. The service will extract the overridable fields from +the object and ignore all other fields. + +
+
+ +
+
+ +**provenance:** `Optional` — Additional information about the source of the override. + +
+
+
+
+ + +
+
+
+ +
client.entities.removeEntityOverride(entityId, fieldPath) -> Entity +
+
+ +#### 📝 Description + +
+
+ +
+
+ +This operation clears the override value from the specified field path on the entity. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.entities().removeEntityOverride( + "entityId", + "mil_view.disposition", + RemoveEntityOverrideRequest + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**entityId:** `String` — The unique ID of the entity to undo an override from. + +
+
+ +
+
+ +**fieldPath:** `String` — The fieldPath to clear overrides from. + +
+
+
+
+ + +
+
+
+ +
client.entities.longPollEntityEvents(request) -> EntityEventResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +This is a long polling API that will first return all pre-existing data and then return all new data as +it becomes available. If you want to start a new polling session then open a request with an empty +'sessionToken' in the request body. The server will return a new session token in the response. +If you want to retrieve the next batch of results from an existing polling session then send the session +token you received from the server in the request body. If no new data is available then the server will +hold the connection open for up to 5 minutes. After the 5 minute timeout period, the server will close the +connection with no results and you may resume polling with the same session token. If your session falls behind +more than 3x the total number of entities in the environment, the server will terminate your session. +In this case you must start a new session by sending a request with an empty session token. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.entities().longPollEntityEvents( + EntityEventRequest + .builder() + .sessionToken("sessionToken") + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**sessionToken:** `String` — Long-poll session identifier. Leave empty to start a new polling session. + +
+
+ +
+
+ +**batchSize:** `Optional` — Maximum size of response batch. Defaults to 100. Must be between 1 and 2000 (inclusive). + +
+
+
+
+ + +
+
+
+ +
client.entities.streamEntities(request) -> Iterable<StreamEntitiesResponse> +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Establishes a server-sent events (SSE) connection that streams entity data in real-time. +This is a one-way connection from server to client that follows the SSE protocol with text/event-stream content type. + +This endpoint enables clients to maintain a real-time view of the common operational picture (COP) +by first streaming all pre-existing entities that match filter criteria, then continuously delivering +updates as entities are created, modified, or deleted. + +The server first sends events with type PREEXISTING for all live entities matching the filter that existed before the stream was open, +then streams CREATE events for newly created entities, UPDATE events when existing entities change, and DELETED events when entities are removed. The stream remains open +indefinitely unless preExistingOnly is set to true. + +Heartbeat messages can be configured to maintain connection health and detect disconnects by setting the heartbeatIntervalMS +parameter. These heartbeats help keep the connection alive and allow clients to verify the server is still responsive. + +Clients can optimize bandwidth usage by specifying which entity components they need populated using the componentsToInclude parameter. +This allows receiving only relevant data instead of complete entities. + +The connection automatically recovers from temporary disconnections, resuming the stream where it left off. Unlike polling approaches, +this provides real-time updates with minimal latency and reduced server load. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.entities().streamEntities( + EntityStreamRequest + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**heartbeatIntervalMs:** `Optional` — at what interval to send heartbeat events, defaults to 30s. + +
+
+ +
+
+ +**preExistingOnly:** `Optional` — only stream pre-existing entities in the environment and then close the connection, defaults to false. + +
+
+ +
+
+ +**componentsToInclude:** `Optional>` — list of components to include, leave empty to include all components. + +
+
+
+
+ + +
+
+
+ +## Tasks +
client.tasks.createTask(request) -> Task +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Creates a new Task in the system with the specified parameters. + +This method initiates a new task with a unique ID (either provided or auto-generated), +sets the initial task state to STATUS_CREATED, and establishes task ownership. The task +can be assigned to a specific agent through the Relations field. + +Once created, a task enters the lifecycle workflow and can be tracked, updated, and managed +through other Tasks API endpoints. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.tasks().createTask( + TaskCreation + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**taskId:** `Optional` + +If non-empty, will set the requested Task ID, otherwise will generate a new random +GUID. Will reject if supplied Task ID does not match [A-Za-z0-9_-.]{5,36}. + +
+
+ +
+
+ +**displayName:** `Optional` — Human readable display name for this Task, should be short (<100 chars). + +
+
+ +
+
+ +**description:** `Optional` — Longer, free form human readable description of this Task. + +
+
+ +
+
+ +**specification:** `Optional` — The path for the Protobuf task definition, and the complete task data. + +
+
+ +
+
+ +**author:** `Optional` + +
+
+ +
+
+ +**relations:** `Optional` + +Any relationships associated with this Task, such as a parent Task or an assignee +this Task is designated to for execution. + +
+
+ +
+
+ +**isExecutedElsewhere:** `Optional` + +If set, then the service will not trigger execution of this task on an agent. Useful +for when ingesting tasks from an external system that is triggering execution of tasks +on agents. + +
+
+ +
+
+ +**initialEntities:** `Optional>` + +Indicates an initial set of entities that can be used to execute an entity aware +task. For example, an entity Objective, an entity Keep In Zone, etc. + +
+
+
+
+ + +
+
+
+ +
client.tasks.getTask(taskId) -> Task +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves a specific Task by its ID, with options to select a particular task version or view. + +This method returns detailed information about a task including its current status, +specification, relations, and other metadata. The response includes the complete Task object +with all associated fields. + +By default, the method returns the latest definition version of the task from the manager's +perspective. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.tasks().getTask( + "taskId", + GetTaskRequest + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**taskId:** `String` — ID of task to return + +
+
+
+
+ + +
+
+
+ +
client.tasks.updateTaskStatus(taskId, request) -> Task +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Updates the status of a Task as it progresses through its lifecycle. + +This method allows agents or operators to report the current state of a task, +which could include changes to task status, and error information. + +Each status update increments the task's status_version. When updating status, +clients must provide the current version to ensure consistency. The system rejects +updates with mismatched versions to prevent race conditions. + +Terminal states (`STATUS_DONE_OK` and `STATUS_DONE_NOT_OK`) are permanent; once a task +reaches these states, no further updates are allowed. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.tasks().updateTaskStatus( + "taskId", + TaskStatusUpdate + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**taskId:** `String` — ID of task to update status of + +
+
+ +
+
+ +**statusVersion:** `Optional` + +The status version of the task to update. This version number increments to indicate the task's +current stage in its status lifecycle. Specifically, whenever a task's status updates, the status +version increments by one. Any status updates received with a lower status version number than what +is known are considered stale and ignored. + +
+
+ +
+
+ +**newStatus:** `Optional` — The new status of the task. + +
+
+ +
+
+ +**author:** `Optional` + +
+
+
+
+ + +
+
+
+ +
client.tasks.queryTasks(request) -> TaskQueryResults +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Searches for Tasks that match specified filtering criteria and returns matching tasks in paginated form. + +This method allows filtering tasks based on multiple criteria including: +- Parent task relationships +- Task status (with inclusive or exclusive filtering) +- Update time ranges +- Task view (manager or agent perspective) +- Task assignee +- Task type (via exact URL matches or prefix matching) + +Results are returned in pages. When more results are available than can be returned in a single +response, a page_token is provided that can be used in subsequent requests to retrieve the next +set of results. + +By default, this returns the latest task version for each matching task from the manager's perspective. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.tasks().queryTasks( + TaskQuery + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**pageToken:** `Optional` — If set, returns results starting from the given pageToken. + +
+
+ +
+
+ +**parentTaskId:** `Optional` + +If present matches Tasks with this parent Task ID. +Note: this is mutually exclusive with all other query parameters, for example, either provide parent task ID, or +any of the remaining parameters, but not both. + +
+
+ +
+
+ +**statusFilter:** `Optional` + +
+
+ +
+
+ +**updateTimeRange:** `Optional` — If provided, only provides Tasks updated within the time range. + +
+
+
+
+ + +
+
+
+ +
client.tasks.listenAsAgent(request) -> AgentRequest +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Establishes a server streaming connection that delivers tasks to taskable agents for execution. + +This method creates a persistent connection from Tasks API to an agent, allowing the server +to push tasks to the agent as they become available. The agent receives a stream of tasks that +match its selector criteria (entity IDs). + +The stream delivers three types of requests: +- ExecuteRequest: Contains a new task for the agent to execute +- CancelRequest: Indicates a task should be canceled +- CompleteRequest: Indicates a task should be completed + +This is the primary method for taskable agents to receive and process tasks in real-time. +Agents should maintain this connection and process incoming tasks according to their capabilities. + +When an agent receives a task, it should update the task status using the UpdateStatus endpoint +to provide progress information back to Tasks API. + +This is a long polling API that will block until a new task is ready for delivery. If no new task is +available then the server will hold on to your request for up to 5 minutes, after that 5 minute timeout +period you will be expected to reinitiate a new request. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.tasks().listenAsAgent( + AgentListener + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**agentSelector:** `Optional` — Selector criteria to determine which Agent Tasks the agent receives + +
+
+
+
+ + +
+
+
+ +## Objects +
client.objects.listObjects() -> SyncPagingIterable<PathMetadata> +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Lists objects in your environment. You can define a prefix to list a subset of your objects. If you do not set a prefix, Lattice returns all available objects. By default this endpoint will list local objects only. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.objects().listObjects( + ListObjectsRequest + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**prefix:** `Optional` — Filters the objects based on the specified prefix path. If no path is specified, all objects are returned. + +
+
+ +
+
+ +**sinceTimestamp:** `Optional` — Sets the age for the oldest objects to query across the environment. + +
+
+ +
+
+ +**pageToken:** `Optional` — Base64 and URL-encoded cursor returned by the service to continue paging. + +
+
+ +
+
+ +**allObjectsInMesh:** `Optional` — Lists objects across all environment nodes in a Lattice Mesh. + +
+
+
+
+ + +
+
+
+ +
client.objects.getObject(objectPath) -> InputStream +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Fetches an object from your environment using the objectPath path parameter. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.objects().getObject( + "objectPath", + GetObjectRequest + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**objectPath:** `String` — The path of the object to fetch. + +
+
+ +
+
+ +**acceptEncoding:** `Optional` — If set, Lattice will compress the response using the specified compression method. If the header is not defined, or the compression method is set to `identity`, no compression will be applied to the response. + +
+
+ +
+
+ +**priority:** `Optional` — Indicates a client's preference for the priority of the response. The value is a structured header as defined in RFC 9218. If you do not set the header, Lattice uses the default priority set for the environment. Incremental delivery directives are not supported and will be ignored. + +
+
+
+
+ + +
+
+
+ +
client.objects.uploadObject(objectPath, request) -> PathMetadata +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Uploads an object. The object must be 1 GiB or smaller. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.objects().uploadObject("".getBytes()); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**objectPath:** `String` — Path of the Object that is to be uploaded. + +
+
+
+
+ + +
+
+
+ +
client.objects.deleteObject(objectPath) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Deletes an object from your environment given the objectPath path parameter. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.objects().deleteObject( + "objectPath", + DeleteObjectRequest + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**objectPath:** `String` — The path of the object to delete. + +
+
+
+
+ + +
+
+
+ +
client.objects.getObjectMetadata(objectPath) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Returns metadata for a specified object path. Use this to fetch metadata such as object size (size_bytes), its expiry time (expiry_time), or its latest update timestamp (last_updated_at). +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.objects().getObjectMetadata( + "objectPath", + GetObjectMetadataRequest + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**objectPath:** `String` — The path of the object to query. + +
+
+
+
+ + +
+
+
+ +## OAuth2 +
client.oAuth2.getToken(request) -> GetTokenResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Support the client credentials authorization flow +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.oAuth2().getToken( + GetTokenRequest + .builder() + .build() +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**grantType:** `String` — The type of grant being requested + +
+
+ +
+
+ +**clientId:** `Optional` — The client identifier + +
+
+ +
+
+ +**clientSecret:** `Optional` — The client secret + +
+
+
+
+ + +
+
+
diff --git a/src/main/java/com/anduril/AsyncLattice.java b/src/main/java/com/anduril/AsyncLattice.java index aebf9f89..bc6fab31 100644 --- a/src/main/java/com/anduril/AsyncLattice.java +++ b/src/main/java/com/anduril/AsyncLattice.java @@ -6,6 +6,7 @@ import com.anduril.core.ClientOptions; import com.anduril.core.Suppliers; import com.anduril.resources.entities.AsyncEntitiesClient; +import com.anduril.resources.oauth2.AsyncOAuth2Client; import com.anduril.resources.objects.AsyncObjectsClient; import com.anduril.resources.tasks.AsyncTasksClient; import java.util.function.Supplier; @@ -19,11 +20,14 @@ public class AsyncLattice { protected final Supplier objectsClient; + protected final Supplier oAuth2Client; + public AsyncLattice(ClientOptions clientOptions) { this.clientOptions = clientOptions; this.entitiesClient = Suppliers.memoize(() -> new AsyncEntitiesClient(clientOptions)); this.tasksClient = Suppliers.memoize(() -> new AsyncTasksClient(clientOptions)); this.objectsClient = Suppliers.memoize(() -> new AsyncObjectsClient(clientOptions)); + this.oAuth2Client = Suppliers.memoize(() -> new AsyncOAuth2Client(clientOptions)); } public AsyncEntitiesClient entities() { @@ -38,7 +42,26 @@ public AsyncObjectsClient objects() { return this.objectsClient.get(); } - public static AsyncLatticeBuilder builder() { - return new AsyncLatticeBuilder(); + public AsyncOAuth2Client oAuth2() { + return this.oAuth2Client.get(); + } + + /** + * Creates a client builder using a pre-generated access token. + * @param token The access token to use for authentication + * @return A builder configured for token authentication + */ + public static AsyncLatticeBuilder._TokenAuth withToken(String token) { + return AsyncLatticeBuilder.withToken(token); + } + + /** + * Creates a client builder using OAuth client credentials. + * @param clientId The OAuth client ID + * @param clientSecret The OAuth client secret + * @return A builder configured for OAuth authentication + */ + public static AsyncLatticeBuilder._CredentialsAuth withCredentials(String clientId, String clientSecret) { + return AsyncLatticeBuilder.withCredentials(clientId, clientSecret); } } diff --git a/src/main/java/com/anduril/AsyncLatticeBuilder.java b/src/main/java/com/anduril/AsyncLatticeBuilder.java index 0d2711f5..c3fc63ba 100644 --- a/src/main/java/com/anduril/AsyncLatticeBuilder.java +++ b/src/main/java/com/anduril/AsyncLatticeBuilder.java @@ -5,6 +5,8 @@ import com.anduril.core.ClientOptions; import com.anduril.core.Environment; +import com.anduril.core.OAuthTokenSupplier; +import com.anduril.resources.oauth2.OAuth2Client; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -17,18 +19,32 @@ public class AsyncLatticeBuilder { private final Map customHeaders = new HashMap<>(); - private String token = null; - - private Environment environment = Environment.DEFAULT; + protected Environment environment = Environment.DEFAULT; private OkHttpClient httpClient; /** - * Sets token + * Creates a builder that uses a pre-generated access token for authentication. + * Use this when you already have a valid access token and want to bypass + * the OAuth client credentials flow. + * + * @param token The access token to use for Authorization header + * @return A builder configured for token authentication */ - public AsyncLatticeBuilder token(String token) { - this.token = token; - return this; + public static _TokenAuth withToken(String token) { + return new _TokenAuth(token); + } + + /** + * Creates a builder that uses OAuth client credentials for authentication. + * The builder will automatically handle token acquisition and refresh. + * + * @param clientId The OAuth client ID + * @param clientSecret The OAuth client secret + * @return A builder configured for OAuth client credentials authentication + */ + public static _CredentialsAuth withCredentials(String clientId, String clientSecret) { + return new _CredentialsAuth(clientId, clientSecret); } public AsyncLatticeBuilder environment(Environment environment) { @@ -117,11 +133,7 @@ protected void setEnvironment(ClientOptions.Builder builder) { * } * } */ - protected void setAuthentication(ClientOptions.Builder builder) { - if (this.token != null) { - builder.addHeader("Authorization", "Bearer " + this.token); - } - } + protected void setAuthentication(ClientOptions.Builder builder) {} /** * Sets the request timeout configuration. @@ -196,10 +208,44 @@ protected void setAdditional(ClientOptions.Builder builder) {} protected void validateConfiguration() {} public AsyncLattice build() { - if (token == null) { - throw new RuntimeException("Please provide token"); - } validateConfiguration(); return new AsyncLattice(buildClientOptions()); } + + public static final class _TokenAuth extends AsyncLatticeBuilder { + private final String token; + + _TokenAuth(String token) { + this.token = token; + } + + @Override + protected void setAuthentication(ClientOptions.Builder builder) { + builder.addHeader("Authorization", "Bearer " + this.token); + } + } + + public static final class _CredentialsAuth extends AsyncLatticeBuilder { + private final String clientId; + + private final String clientSecret; + + _CredentialsAuth(String clientId, String clientSecret) { + this.clientId = clientId; + this.clientSecret = clientSecret; + } + + @Override + public AsyncLattice build() { + validateConfiguration(); + ClientOptions baseOptions = buildClientOptions(); + OAuth2Client authClient = new OAuth2Client(baseOptions); + OAuthTokenSupplier oAuthTokenSupplier = + new OAuthTokenSupplier(this.clientId, this.clientSecret, authClient); + ClientOptions finalOptions = ClientOptions.Builder.from(baseOptions) + .addHeader("Authorization", oAuthTokenSupplier) + .build(); + return new AsyncLattice(finalOptions); + } + } } diff --git a/src/main/java/com/anduril/Lattice.java b/src/main/java/com/anduril/Lattice.java index cbeeaac8..e40d7100 100644 --- a/src/main/java/com/anduril/Lattice.java +++ b/src/main/java/com/anduril/Lattice.java @@ -6,6 +6,7 @@ import com.anduril.core.ClientOptions; import com.anduril.core.Suppliers; import com.anduril.resources.entities.EntitiesClient; +import com.anduril.resources.oauth2.OAuth2Client; import com.anduril.resources.objects.ObjectsClient; import com.anduril.resources.tasks.TasksClient; import java.util.function.Supplier; @@ -19,11 +20,14 @@ public class Lattice { protected final Supplier objectsClient; + protected final Supplier oAuth2Client; + public Lattice(ClientOptions clientOptions) { this.clientOptions = clientOptions; this.entitiesClient = Suppliers.memoize(() -> new EntitiesClient(clientOptions)); this.tasksClient = Suppliers.memoize(() -> new TasksClient(clientOptions)); this.objectsClient = Suppliers.memoize(() -> new ObjectsClient(clientOptions)); + this.oAuth2Client = Suppliers.memoize(() -> new OAuth2Client(clientOptions)); } public EntitiesClient entities() { @@ -38,7 +42,26 @@ public ObjectsClient objects() { return this.objectsClient.get(); } - public static LatticeBuilder builder() { - return new LatticeBuilder(); + public OAuth2Client oAuth2() { + return this.oAuth2Client.get(); + } + + /** + * Creates a client builder using a pre-generated access token. + * @param token The access token to use for authentication + * @return A builder configured for token authentication + */ + public static LatticeBuilder._TokenAuth withToken(String token) { + return LatticeBuilder.withToken(token); + } + + /** + * Creates a client builder using OAuth client credentials. + * @param clientId The OAuth client ID + * @param clientSecret The OAuth client secret + * @return A builder configured for OAuth authentication + */ + public static LatticeBuilder._CredentialsAuth withCredentials(String clientId, String clientSecret) { + return LatticeBuilder.withCredentials(clientId, clientSecret); } } diff --git a/src/main/java/com/anduril/LatticeBuilder.java b/src/main/java/com/anduril/LatticeBuilder.java index 2bc686a5..af42597f 100644 --- a/src/main/java/com/anduril/LatticeBuilder.java +++ b/src/main/java/com/anduril/LatticeBuilder.java @@ -5,6 +5,8 @@ import com.anduril.core.ClientOptions; import com.anduril.core.Environment; +import com.anduril.core.OAuthTokenSupplier; +import com.anduril.resources.oauth2.OAuth2Client; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -17,18 +19,32 @@ public class LatticeBuilder { private final Map customHeaders = new HashMap<>(); - private String token = null; - - private Environment environment = Environment.DEFAULT; + protected Environment environment = Environment.DEFAULT; private OkHttpClient httpClient; /** - * Sets token + * Creates a builder that uses a pre-generated access token for authentication. + * Use this when you already have a valid access token and want to bypass + * the OAuth client credentials flow. + * + * @param token The access token to use for Authorization header + * @return A builder configured for token authentication */ - public LatticeBuilder token(String token) { - this.token = token; - return this; + public static _TokenAuth withToken(String token) { + return new _TokenAuth(token); + } + + /** + * Creates a builder that uses OAuth client credentials for authentication. + * The builder will automatically handle token acquisition and refresh. + * + * @param clientId The OAuth client ID + * @param clientSecret The OAuth client secret + * @return A builder configured for OAuth client credentials authentication + */ + public static _CredentialsAuth withCredentials(String clientId, String clientSecret) { + return new _CredentialsAuth(clientId, clientSecret); } public LatticeBuilder environment(Environment environment) { @@ -117,11 +133,7 @@ protected void setEnvironment(ClientOptions.Builder builder) { * } * } */ - protected void setAuthentication(ClientOptions.Builder builder) { - if (this.token != null) { - builder.addHeader("Authorization", "Bearer " + this.token); - } - } + protected void setAuthentication(ClientOptions.Builder builder) {} /** * Sets the request timeout configuration. @@ -196,10 +208,44 @@ protected void setAdditional(ClientOptions.Builder builder) {} protected void validateConfiguration() {} public Lattice build() { - if (token == null) { - throw new RuntimeException("Please provide token"); - } validateConfiguration(); return new Lattice(buildClientOptions()); } + + public static final class _TokenAuth extends LatticeBuilder { + private final String token; + + _TokenAuth(String token) { + this.token = token; + } + + @Override + protected void setAuthentication(ClientOptions.Builder builder) { + builder.addHeader("Authorization", "Bearer " + this.token); + } + } + + public static final class _CredentialsAuth extends LatticeBuilder { + private final String clientId; + + private final String clientSecret; + + _CredentialsAuth(String clientId, String clientSecret) { + this.clientId = clientId; + this.clientSecret = clientSecret; + } + + @Override + public Lattice build() { + validateConfiguration(); + ClientOptions baseOptions = buildClientOptions(); + OAuth2Client authClient = new OAuth2Client(baseOptions); + OAuthTokenSupplier oAuthTokenSupplier = + new OAuthTokenSupplier(this.clientId, this.clientSecret, authClient); + ClientOptions finalOptions = ClientOptions.Builder.from(baseOptions) + .addHeader("Authorization", oAuthTokenSupplier) + .build(); + return new Lattice(finalOptions); + } + } } diff --git a/src/main/java/com/anduril/core/ClientOptions.java b/src/main/java/com/anduril/core/ClientOptions.java index 5cd368c6..4e4b62c5 100644 --- a/src/main/java/com/anduril/core/ClientOptions.java +++ b/src/main/java/com/anduril/core/ClientOptions.java @@ -35,10 +35,10 @@ private ClientOptions( this.headers.putAll(headers); this.headers.putAll(new HashMap() { { - put("User-Agent", "com.anduril:lattice-sdk/5.0.0"); + put("User-Agent", "com.anduril:lattice-sdk/5.1.0"); put("X-Fern-Language", "JAVA"); put("X-Fern-SDK-Name", "com.anduril.fern:api-sdk"); - put("X-Fern-SDK-Version", "5.0.0"); + put("X-Fern-SDK-Version", "5.1.0"); } }); this.headerSuppliers = headerSuppliers; @@ -185,6 +185,9 @@ public static Builder from(ClientOptions clientOptions) { builder.environment = clientOptions.environment(); builder.timeout = Optional.of(clientOptions.timeout(null)); builder.httpClient = clientOptions.httpClient(); + builder.headers.putAll(clientOptions.headers); + builder.headerSuppliers.putAll(clientOptions.headerSuppliers); + builder.maxRetries = clientOptions.maxRetries(); return builder; } } diff --git a/src/main/java/com/anduril/core/OAuthTokenSupplier.java b/src/main/java/com/anduril/core/OAuthTokenSupplier.java new file mode 100644 index 00000000..f114a00e --- /dev/null +++ b/src/main/java/com/anduril/core/OAuthTokenSupplier.java @@ -0,0 +1,54 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.core; + +import com.anduril.resources.oauth2.OAuth2Client; +import com.anduril.resources.oauth2.requests.GetTokenRequest; +import com.anduril.resources.oauth2.types.GetTokenResponse; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.function.Supplier; + +public final class OAuthTokenSupplier implements Supplier { + private static final long BUFFER_IN_MINUTES = 2; + + private final String clientId; + + private final String clientSecret; + + private final OAuth2Client authClient; + + private String accessToken; + + private Instant expiresAt; + + public OAuthTokenSupplier(String clientId, String clientSecret, OAuth2Client authClient) { + this.clientId = clientId; + this.clientSecret = clientSecret; + this.authClient = authClient; + this.expiresAt = Instant.now(); + } + + public GetTokenResponse fetchToken() { + GetTokenRequest getTokenRequest = GetTokenRequest.builder() + .clientId(clientId) + .clientSecret(clientSecret) + .build(); + return authClient.getToken(getTokenRequest); + } + + @java.lang.Override + public String get() { + if (accessToken == null || expiresAt.isBefore(Instant.now())) { + GetTokenResponse authResponse = fetchToken(); + this.accessToken = authResponse.getAccessToken(); + this.expiresAt = getExpiresAt(authResponse.getExpiresIn().orElse(3600)); + } + return "Bearer " + accessToken; + } + + private Instant getExpiresAt(long expiresInSeconds) { + return Instant.now().plus(expiresInSeconds, ChronoUnit.SECONDS).minus(BUFFER_IN_MINUTES, ChronoUnit.MINUTES); + } +} diff --git a/src/main/java/com/anduril/core/RequestOptions.java b/src/main/java/com/anduril/core/RequestOptions.java index c7206906..f0fe01ef 100644 --- a/src/main/java/com/anduril/core/RequestOptions.java +++ b/src/main/java/com/anduril/core/RequestOptions.java @@ -10,8 +10,6 @@ import java.util.function.Supplier; public final class RequestOptions { - private final String token; - private final Optional timeout; private final TimeUnit timeoutTimeUnit; @@ -21,12 +19,10 @@ public final class RequestOptions { private final Map> headerSuppliers; private RequestOptions( - String token, Optional timeout, TimeUnit timeoutTimeUnit, Map headers, Map> headerSuppliers) { - this.token = token; this.timeout = timeout; this.timeoutTimeUnit = timeoutTimeUnit; this.headers = headers; @@ -43,9 +39,6 @@ public TimeUnit getTimeoutTimeUnit() { public Map getHeaders() { Map headers = new HashMap<>(); - if (this.token != null) { - headers.put("Authorization", "Bearer " + this.token); - } headers.putAll(this.headers); this.headerSuppliers.forEach((key, supplier) -> { headers.put(key, supplier.get()); @@ -58,8 +51,6 @@ public static Builder builder() { } public static class Builder { - private String token = null; - private Optional timeout = Optional.empty(); private TimeUnit timeoutTimeUnit = TimeUnit.SECONDS; @@ -68,11 +59,6 @@ public static class Builder { private final Map> headerSuppliers = new HashMap<>(); - public Builder token(String token) { - this.token = token; - return this; - } - public Builder timeout(Integer timeout) { this.timeout = Optional.of(timeout); return this; @@ -95,7 +81,7 @@ public Builder addHeader(String key, Supplier value) { } public RequestOptions build() { - return new RequestOptions(token, timeout, timeoutTimeUnit, headers, headerSuppliers); + return new RequestOptions(timeout, timeoutTimeUnit, headers, headerSuppliers); } } } diff --git a/src/main/java/com/anduril/core/pagination/AsyncCustomPager.java b/src/main/java/com/anduril/core/pagination/AsyncCustomPager.java index b3cb9ec6..86a0fe79 100644 --- a/src/main/java/com/anduril/core/pagination/AsyncCustomPager.java +++ b/src/main/java/com/anduril/core/pagination/AsyncCustomPager.java @@ -3,6 +3,7 @@ */ package com.anduril.core.pagination; +import com.anduril.core.ClientOptions; import java.io.IOException; import java.util.List; import java.util.Optional; @@ -62,12 +63,12 @@ public class AsyncCustomPager implements BiDirectionalPage { * Create an AsyncCustomPager from an initial response. * * @param initialResponse The first page response from the API - * @param client The async HTTP client to use for subsequent requests + * @param clientOptions The client options containing HTTP client and other configuration * @param requestOptions Request options for authentication, headers, etc. * @return A CompletableFuture containing the new AsyncCustomPager instance */ public static CompletableFuture> createAsync( - Object initialResponse, okhttp3.OkHttpClient client, Object requestOptions) { + Object initialResponse, ClientOptions clientOptions, Object requestOptions) { throw new UnsupportedOperationException("AsyncCustomPager must be implemented. " + "Please implement this class in core/AsyncCustomPager.java to define your async pagination logic. " + "This file has been added to .fernignore and will not be overwritten. " diff --git a/src/main/java/com/anduril/core/pagination/CustomPager.java b/src/main/java/com/anduril/core/pagination/CustomPager.java index 7e3a29e4..6c624ca8 100644 --- a/src/main/java/com/anduril/core/pagination/CustomPager.java +++ b/src/main/java/com/anduril/core/pagination/CustomPager.java @@ -3,6 +3,7 @@ */ package com.anduril.core.pagination; +import com.anduril.core.ClientOptions; import java.io.IOException; import java.util.Iterator; import java.util.List; @@ -60,12 +61,12 @@ public class CustomPager implements BiDirectionalPage, Iterable { * Create a CustomPager from an initial response. * * @param initialResponse The first page response from the API - * @param client The HTTP client to use for subsequent requests + * @param clientOptions The client options containing HTTP client and other configuration * @param requestOptions Request options for authentication, headers, etc. * @return A new CustomPager instance * @throws IOException if the request fails */ - public static CustomPager create(Object initialResponse, okhttp3.OkHttpClient client, Object requestOptions) + public static CustomPager create(Object initialResponse, ClientOptions clientOptions, Object requestOptions) throws IOException { throw new UnsupportedOperationException("CustomPager must be implemented. " + "Please implement this class in core/CustomPager.java to define your pagination logic. " diff --git a/src/main/java/com/anduril/resources/entities/AsyncEntitiesClient.java b/src/main/java/com/anduril/resources/entities/AsyncEntitiesClient.java index c13ba7b2..c41b925b 100644 --- a/src/main/java/com/anduril/resources/entities/AsyncEntitiesClient.java +++ b/src/main/java/com/anduril/resources/entities/AsyncEntitiesClient.java @@ -44,6 +44,18 @@ public CompletableFuture publishEntity() { return this.rawClient.publishEntity().thenApply(response -> response.body()); } + /** + * Publish an entity for ingest into the Entities API. Entities created with this method are "owned" by the originator: other sources, + * such as the UI, may not edit or delete these entities. The server validates entities at API call time and + * returns an error if the entity is invalid. + *

An entity ID must be provided when calling this endpoint. If the entity referenced by the entity ID does not exist + * then it will be created. Otherwise the entity will be updated. An entity will only be updated if its + * provenance.sourceUpdateTime is greater than the provenance.sourceUpdateTime of the existing entity.

+ */ + public CompletableFuture publishEntity(RequestOptions requestOptions) { + return this.rawClient.publishEntity(requestOptions).thenApply(response -> response.body()); + } + /** * Publish an entity for ingest into the Entities API. Entities created with this method are "owned" by the originator: other sources, * such as the UI, may not edit or delete these entities. The server validates entities at API call time and @@ -72,6 +84,10 @@ public CompletableFuture getEntity(String entityId) { return this.rawClient.getEntity(entityId).thenApply(response -> response.body()); } + public CompletableFuture getEntity(String entityId, RequestOptions requestOptions) { + return this.rawClient.getEntity(entityId, requestOptions).thenApply(response -> response.body()); + } + public CompletableFuture getEntity(String entityId, GetEntityRequest request) { return this.rawClient.getEntity(entityId, request).thenApply(response -> response.body()); } @@ -93,6 +109,20 @@ public CompletableFuture overrideEntity(String entityId, String fieldPat return this.rawClient.overrideEntity(entityId, fieldPath).thenApply(response -> response.body()); } + /** + * Only fields marked with overridable can be overridden. Please refer to our documentation to see the comprehensive + * list of fields that can be overridden. The entity in the request body should only have a value set on the field + * specified in the field path parameter. Field paths are rooted in the base entity object and must be represented + * using lower_snake_case. Do not include "entity" in the field path. + *

Note that overrides are applied in an eventually consistent manner. If multiple overrides are created + * concurrently for the same field path, the last writer wins.

+ */ + public CompletableFuture overrideEntity(String entityId, String fieldPath, RequestOptions requestOptions) { + return this.rawClient + .overrideEntity(entityId, fieldPath, requestOptions) + .thenApply(response -> response.body()); + } + /** * Only fields marked with overridable can be overridden. Please refer to our documentation to see the comprehensive * list of fields that can be overridden. The entity in the request body should only have a value set on the field @@ -127,6 +157,16 @@ public CompletableFuture removeEntityOverride(String entityId, String fi return this.rawClient.removeEntityOverride(entityId, fieldPath).thenApply(response -> response.body()); } + /** + * This operation clears the override value from the specified field path on the entity. + */ + public CompletableFuture removeEntityOverride( + String entityId, String fieldPath, RequestOptions requestOptions) { + return this.rawClient + .removeEntityOverride(entityId, fieldPath, requestOptions) + .thenApply(response -> response.body()); + } + /** * This operation clears the override value from the specified field path on the entity. */ @@ -196,6 +236,26 @@ public CompletableFuture> streamEntities() { return this.rawClient.streamEntities().thenApply(response -> response.body()); } + /** + * Establishes a server-sent events (SSE) connection that streams entity data in real-time. + * This is a one-way connection from server to client that follows the SSE protocol with text/event-stream content type. + *

This endpoint enables clients to maintain a real-time view of the common operational picture (COP) + * by first streaming all pre-existing entities that match filter criteria, then continuously delivering + * updates as entities are created, modified, or deleted.

+ *

The server first sends events with type PREEXISTING for all live entities matching the filter that existed before the stream was open, + * then streams CREATE events for newly created entities, UPDATE events when existing entities change, and DELETED events when entities are removed. The stream remains open + * indefinitely unless preExistingOnly is set to true.

+ *

Heartbeat messages can be configured to maintain connection health and detect disconnects by setting the heartbeatIntervalMS + * parameter. These heartbeats help keep the connection alive and allow clients to verify the server is still responsive.

+ *

Clients can optimize bandwidth usage by specifying which entity components they need populated using the componentsToInclude parameter. + * This allows receiving only relevant data instead of complete entities.

+ *

The connection automatically recovers from temporary disconnections, resuming the stream where it left off. Unlike polling approaches, + * this provides real-time updates with minimal latency and reduced server load.

+ */ + public CompletableFuture> streamEntities(RequestOptions requestOptions) { + return this.rawClient.streamEntities(requestOptions).thenApply(response -> response.body()); + } + /** * Establishes a server-sent events (SSE) connection that streams entity data in real-time. * This is a one-way connection from server to client that follows the SSE protocol with text/event-stream content type. diff --git a/src/main/java/com/anduril/resources/entities/AsyncRawEntitiesClient.java b/src/main/java/com/anduril/resources/entities/AsyncRawEntitiesClient.java index 97a6e3b9..d3a814ad 100644 --- a/src/main/java/com/anduril/resources/entities/AsyncRawEntitiesClient.java +++ b/src/main/java/com/anduril/resources/entities/AsyncRawEntitiesClient.java @@ -58,6 +58,18 @@ public CompletableFuture> publishEntity() { return publishEntity(Entity.builder().build()); } + /** + * Publish an entity for ingest into the Entities API. Entities created with this method are "owned" by the originator: other sources, + * such as the UI, may not edit or delete these entities. The server validates entities at API call time and + * returns an error if the entity is invalid. + *

An entity ID must be provided when calling this endpoint. If the entity referenced by the entity ID does not exist + * then it will be created. Otherwise the entity will be updated. An entity will only be updated if its + * provenance.sourceUpdateTime is greater than the provenance.sourceUpdateTime of the existing entity.

+ */ + public CompletableFuture> publishEntity(RequestOptions requestOptions) { + return publishEntity(Entity.builder().build(), requestOptions); + } + /** * Publish an entity for ingest into the Entities API. Entities created with this method are "owned" by the originator: other sources, * such as the UI, may not edit or delete these entities. The server validates entities at API call time and @@ -149,6 +161,10 @@ public CompletableFuture> getEntity(String entityId) return getEntity(entityId, GetEntityRequest.builder().build()); } + public CompletableFuture> getEntity(String entityId, RequestOptions requestOptions) { + return getEntity(entityId, GetEntityRequest.builder().build(), requestOptions); + } + public CompletableFuture> getEntity(String entityId, GetEntityRequest request) { return getEntity(entityId, request, null); } @@ -231,6 +247,19 @@ public CompletableFuture> overrideEntity(String enti return overrideEntity(entityId, fieldPath, EntityOverride.builder().build()); } + /** + * Only fields marked with overridable can be overridden. Please refer to our documentation to see the comprehensive + * list of fields that can be overridden. The entity in the request body should only have a value set on the field + * specified in the field path parameter. Field paths are rooted in the base entity object and must be represented + * using lower_snake_case. Do not include "entity" in the field path. + *

Note that overrides are applied in an eventually consistent manner. If multiple overrides are created + * concurrently for the same field path, the last writer wins.

+ */ + public CompletableFuture> overrideEntity( + String entityId, String fieldPath, RequestOptions requestOptions) { + return overrideEntity(entityId, fieldPath, EntityOverride.builder().build(), requestOptions); + } + /** * Only fields marked with overridable can be overridden. Please refer to our documentation to see the comprehensive * list of fields that can be overridden. The entity in the request body should only have a value set on the field @@ -336,6 +365,15 @@ public CompletableFuture> removeEntityOverride(Strin entityId, fieldPath, RemoveEntityOverrideRequest.builder().build()); } + /** + * This operation clears the override value from the specified field path on the entity. + */ + public CompletableFuture> removeEntityOverride( + String entityId, String fieldPath, RequestOptions requestOptions) { + return removeEntityOverride( + entityId, fieldPath, RemoveEntityOverrideRequest.builder().build(), requestOptions); + } + /** * This operation clears the override value from the specified field path on the entity. */ @@ -546,6 +584,27 @@ public CompletableFuture>> return streamEntities(EntityStreamRequest.builder().build()); } + /** + * Establishes a server-sent events (SSE) connection that streams entity data in real-time. + * This is a one-way connection from server to client that follows the SSE protocol with text/event-stream content type. + *

This endpoint enables clients to maintain a real-time view of the common operational picture (COP) + * by first streaming all pre-existing entities that match filter criteria, then continuously delivering + * updates as entities are created, modified, or deleted.

+ *

The server first sends events with type PREEXISTING for all live entities matching the filter that existed before the stream was open, + * then streams CREATE events for newly created entities, UPDATE events when existing entities change, and DELETED events when entities are removed. The stream remains open + * indefinitely unless preExistingOnly is set to true.

+ *

Heartbeat messages can be configured to maintain connection health and detect disconnects by setting the heartbeatIntervalMS + * parameter. These heartbeats help keep the connection alive and allow clients to verify the server is still responsive.

+ *

Clients can optimize bandwidth usage by specifying which entity components they need populated using the componentsToInclude parameter. + * This allows receiving only relevant data instead of complete entities.

+ *

The connection automatically recovers from temporary disconnections, resuming the stream where it left off. Unlike polling approaches, + * this provides real-time updates with minimal latency and reduced server load.

+ */ + public CompletableFuture>> streamEntities( + RequestOptions requestOptions) { + return streamEntities(EntityStreamRequest.builder().build(), requestOptions); + } + /** * Establishes a server-sent events (SSE) connection that streams entity data in real-time. * This is a one-way connection from server to client that follows the SSE protocol with text/event-stream content type. diff --git a/src/main/java/com/anduril/resources/entities/EntitiesClient.java b/src/main/java/com/anduril/resources/entities/EntitiesClient.java index 0cc52367..13225b3e 100644 --- a/src/main/java/com/anduril/resources/entities/EntitiesClient.java +++ b/src/main/java/com/anduril/resources/entities/EntitiesClient.java @@ -43,6 +43,18 @@ public Entity publishEntity() { return this.rawClient.publishEntity().body(); } + /** + * Publish an entity for ingest into the Entities API. Entities created with this method are "owned" by the originator: other sources, + * such as the UI, may not edit or delete these entities. The server validates entities at API call time and + * returns an error if the entity is invalid. + *

An entity ID must be provided when calling this endpoint. If the entity referenced by the entity ID does not exist + * then it will be created. Otherwise the entity will be updated. An entity will only be updated if its + * provenance.sourceUpdateTime is greater than the provenance.sourceUpdateTime of the existing entity.

+ */ + public Entity publishEntity(RequestOptions requestOptions) { + return this.rawClient.publishEntity(requestOptions).body(); + } + /** * Publish an entity for ingest into the Entities API. Entities created with this method are "owned" by the originator: other sources, * such as the UI, may not edit or delete these entities. The server validates entities at API call time and @@ -71,6 +83,10 @@ public Entity getEntity(String entityId) { return this.rawClient.getEntity(entityId).body(); } + public Entity getEntity(String entityId, RequestOptions requestOptions) { + return this.rawClient.getEntity(entityId, requestOptions).body(); + } + public Entity getEntity(String entityId, GetEntityRequest request) { return this.rawClient.getEntity(entityId, request).body(); } @@ -91,6 +107,20 @@ public Entity overrideEntity(String entityId, String fieldPath) { return this.rawClient.overrideEntity(entityId, fieldPath).body(); } + /** + * Only fields marked with overridable can be overridden. Please refer to our documentation to see the comprehensive + * list of fields that can be overridden. The entity in the request body should only have a value set on the field + * specified in the field path parameter. Field paths are rooted in the base entity object and must be represented + * using lower_snake_case. Do not include "entity" in the field path. + *

Note that overrides are applied in an eventually consistent manner. If multiple overrides are created + * concurrently for the same field path, the last writer wins.

+ */ + public Entity overrideEntity(String entityId, String fieldPath, RequestOptions requestOptions) { + return this.rawClient + .overrideEntity(entityId, fieldPath, requestOptions) + .body(); + } + /** * Only fields marked with overridable can be overridden. Please refer to our documentation to see the comprehensive * list of fields that can be overridden. The entity in the request body should only have a value set on the field @@ -125,6 +155,15 @@ public Entity removeEntityOverride(String entityId, String fieldPath) { return this.rawClient.removeEntityOverride(entityId, fieldPath).body(); } + /** + * This operation clears the override value from the specified field path on the entity. + */ + public Entity removeEntityOverride(String entityId, String fieldPath, RequestOptions requestOptions) { + return this.rawClient + .removeEntityOverride(entityId, fieldPath, requestOptions) + .body(); + } + /** * This operation clears the override value from the specified field path on the entity. */ @@ -192,6 +231,26 @@ public Iterable streamEntities() { return this.rawClient.streamEntities().body(); } + /** + * Establishes a server-sent events (SSE) connection that streams entity data in real-time. + * This is a one-way connection from server to client that follows the SSE protocol with text/event-stream content type. + *

This endpoint enables clients to maintain a real-time view of the common operational picture (COP) + * by first streaming all pre-existing entities that match filter criteria, then continuously delivering + * updates as entities are created, modified, or deleted.

+ *

The server first sends events with type PREEXISTING for all live entities matching the filter that existed before the stream was open, + * then streams CREATE events for newly created entities, UPDATE events when existing entities change, and DELETED events when entities are removed. The stream remains open + * indefinitely unless preExistingOnly is set to true.

+ *

Heartbeat messages can be configured to maintain connection health and detect disconnects by setting the heartbeatIntervalMS + * parameter. These heartbeats help keep the connection alive and allow clients to verify the server is still responsive.

+ *

Clients can optimize bandwidth usage by specifying which entity components they need populated using the componentsToInclude parameter. + * This allows receiving only relevant data instead of complete entities.

+ *

The connection automatically recovers from temporary disconnections, resuming the stream where it left off. Unlike polling approaches, + * this provides real-time updates with minimal latency and reduced server load.

+ */ + public Iterable streamEntities(RequestOptions requestOptions) { + return this.rawClient.streamEntities(requestOptions).body(); + } + /** * Establishes a server-sent events (SSE) connection that streams entity data in real-time. * This is a one-way connection from server to client that follows the SSE protocol with text/event-stream content type. diff --git a/src/main/java/com/anduril/resources/entities/RawEntitiesClient.java b/src/main/java/com/anduril/resources/entities/RawEntitiesClient.java index 27084de4..4dae53fd 100644 --- a/src/main/java/com/anduril/resources/entities/RawEntitiesClient.java +++ b/src/main/java/com/anduril/resources/entities/RawEntitiesClient.java @@ -54,6 +54,18 @@ public LatticeHttpResponse publishEntity() { return publishEntity(Entity.builder().build()); } + /** + * Publish an entity for ingest into the Entities API. Entities created with this method are "owned" by the originator: other sources, + * such as the UI, may not edit or delete these entities. The server validates entities at API call time and + * returns an error if the entity is invalid. + *

An entity ID must be provided when calling this endpoint. If the entity referenced by the entity ID does not exist + * then it will be created. Otherwise the entity will be updated. An entity will only be updated if its + * provenance.sourceUpdateTime is greater than the provenance.sourceUpdateTime of the existing entity.

+ */ + public LatticeHttpResponse publishEntity(RequestOptions requestOptions) { + return publishEntity(Entity.builder().build(), requestOptions); + } + /** * Publish an entity for ingest into the Entities API. Entities created with this method are "owned" by the originator: other sources, * such as the UI, may not edit or delete these entities. The server validates entities at API call time and @@ -128,6 +140,10 @@ public LatticeHttpResponse getEntity(String entityId) { return getEntity(entityId, GetEntityRequest.builder().build()); } + public LatticeHttpResponse getEntity(String entityId, RequestOptions requestOptions) { + return getEntity(entityId, GetEntityRequest.builder().build(), requestOptions); + } + public LatticeHttpResponse getEntity(String entityId, GetEntityRequest request) { return getEntity(entityId, request, null); } @@ -191,6 +207,19 @@ public LatticeHttpResponse overrideEntity(String entityId, String fieldP return overrideEntity(entityId, fieldPath, EntityOverride.builder().build()); } + /** + * Only fields marked with overridable can be overridden. Please refer to our documentation to see the comprehensive + * list of fields that can be overridden. The entity in the request body should only have a value set on the field + * specified in the field path parameter. Field paths are rooted in the base entity object and must be represented + * using lower_snake_case. Do not include "entity" in the field path. + *

Note that overrides are applied in an eventually consistent manner. If multiple overrides are created + * concurrently for the same field path, the last writer wins.

+ */ + public LatticeHttpResponse overrideEntity( + String entityId, String fieldPath, RequestOptions requestOptions) { + return overrideEntity(entityId, fieldPath, EntityOverride.builder().build(), requestOptions); + } + /** * Only fields marked with overridable can be overridden. Please refer to our documentation to see the comprehensive * list of fields that can be overridden. The entity in the request body should only have a value set on the field @@ -276,6 +305,15 @@ public LatticeHttpResponse removeEntityOverride(String entityId, String entityId, fieldPath, RemoveEntityOverrideRequest.builder().build()); } + /** + * This operation clears the override value from the specified field path on the entity. + */ + public LatticeHttpResponse removeEntityOverride( + String entityId, String fieldPath, RequestOptions requestOptions) { + return removeEntityOverride( + entityId, fieldPath, RemoveEntityOverrideRequest.builder().build(), requestOptions); + } + /** * This operation clears the override value from the specified field path on the entity. */ @@ -442,6 +480,26 @@ public LatticeHttpResponse> streamEntities() { return streamEntities(EntityStreamRequest.builder().build()); } + /** + * Establishes a server-sent events (SSE) connection that streams entity data in real-time. + * This is a one-way connection from server to client that follows the SSE protocol with text/event-stream content type. + *

This endpoint enables clients to maintain a real-time view of the common operational picture (COP) + * by first streaming all pre-existing entities that match filter criteria, then continuously delivering + * updates as entities are created, modified, or deleted.

+ *

The server first sends events with type PREEXISTING for all live entities matching the filter that existed before the stream was open, + * then streams CREATE events for newly created entities, UPDATE events when existing entities change, and DELETED events when entities are removed. The stream remains open + * indefinitely unless preExistingOnly is set to true.

+ *

Heartbeat messages can be configured to maintain connection health and detect disconnects by setting the heartbeatIntervalMS + * parameter. These heartbeats help keep the connection alive and allow clients to verify the server is still responsive.

+ *

Clients can optimize bandwidth usage by specifying which entity components they need populated using the componentsToInclude parameter. + * This allows receiving only relevant data instead of complete entities.

+ *

The connection automatically recovers from temporary disconnections, resuming the stream where it left off. Unlike polling approaches, + * this provides real-time updates with minimal latency and reduced server load.

+ */ + public LatticeHttpResponse> streamEntities(RequestOptions requestOptions) { + return streamEntities(EntityStreamRequest.builder().build(), requestOptions); + } + /** * Establishes a server-sent events (SSE) connection that streams entity data in real-time. * This is a one-way connection from server to client that follows the SSE protocol with text/event-stream content type. diff --git a/src/main/java/com/anduril/resources/oauth2/AsyncOAuth2Client.java b/src/main/java/com/anduril/resources/oauth2/AsyncOAuth2Client.java new file mode 100644 index 00000000..7b9861a5 --- /dev/null +++ b/src/main/java/com/anduril/resources/oauth2/AsyncOAuth2Client.java @@ -0,0 +1,42 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.resources.oauth2; + +import com.anduril.core.ClientOptions; +import com.anduril.core.RequestOptions; +import com.anduril.resources.oauth2.requests.GetTokenRequest; +import com.anduril.resources.oauth2.types.GetTokenResponse; +import java.util.concurrent.CompletableFuture; + +public class AsyncOAuth2Client { + protected final ClientOptions clientOptions; + + private final AsyncRawOAuth2Client rawClient; + + public AsyncOAuth2Client(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.rawClient = new AsyncRawOAuth2Client(clientOptions); + } + + /** + * Get responses with HTTP metadata like headers + */ + public AsyncRawOAuth2Client withRawResponse() { + return this.rawClient; + } + + /** + * Support the client credentials authorization flow + */ + public CompletableFuture getToken(GetTokenRequest request) { + return this.rawClient.getToken(request).thenApply(response -> response.body()); + } + + /** + * Support the client credentials authorization flow + */ + public CompletableFuture getToken(GetTokenRequest request, RequestOptions requestOptions) { + return this.rawClient.getToken(request, requestOptions).thenApply(response -> response.body()); + } +} diff --git a/src/main/java/com/anduril/resources/oauth2/AsyncRawOAuth2Client.java b/src/main/java/com/anduril/resources/oauth2/AsyncRawOAuth2Client.java new file mode 100644 index 00000000..0a76d367 --- /dev/null +++ b/src/main/java/com/anduril/resources/oauth2/AsyncRawOAuth2Client.java @@ -0,0 +1,122 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.resources.oauth2; + +import com.anduril.core.ClientOptions; +import com.anduril.core.LatticeApiException; +import com.anduril.core.LatticeException; +import com.anduril.core.LatticeHttpResponse; +import com.anduril.core.ObjectMappers; +import com.anduril.core.RequestOptions; +import com.anduril.errors.BadRequestError; +import com.anduril.errors.UnauthorizedError; +import com.anduril.resources.oauth2.requests.GetTokenRequest; +import com.anduril.resources.oauth2.types.GetTokenResponse; +import com.fasterxml.jackson.core.JsonProcessingException; +import java.io.IOException; +import java.util.concurrent.CompletableFuture; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.FormBody; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; + +public class AsyncRawOAuth2Client { + protected final ClientOptions clientOptions; + + public AsyncRawOAuth2Client(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + /** + * Support the client credentials authorization flow + */ + public CompletableFuture> getToken(GetTokenRequest request) { + return getToken(request, null); + } + + /** + * Support the client credentials authorization flow + */ + public CompletableFuture> getToken( + GetTokenRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("api/v1/oauth/token") + .build(); + FormBody.Builder body = new FormBody.Builder(); + try { + body.add("grant_type", String.valueOf(request.getGrantType())); + if (request.getClientId().isPresent()) { + body.add("client_id", String.valueOf(request.getClientId().get())); + } + if (request.getClientSecret().isPresent()) { + body.add( + "client_secret", + String.valueOf(request.getClientSecret().get())); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + Request.Builder _requestBuilder = new Request.Builder() + .url(httpUrl) + .method("POST", body.build()) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/x-www-form-urlencoded") + .addHeader("Accept", "application/json"); + Request okhttpRequest = _requestBuilder.build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + future.complete(new LatticeHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, GetTokenResponse.class), + response)); + return; + } + try { + switch (response.code()) { + case 400: + future.completeExceptionally(new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response)); + return; + case 401: + future.completeExceptionally(new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), + response)); + return; + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new LatticeApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (IOException e) { + future.completeExceptionally(new LatticeException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally(new LatticeException("Network error executing HTTP request", e)); + } + }); + return future; + } +} diff --git a/src/main/java/com/anduril/resources/oauth2/OAuth2Client.java b/src/main/java/com/anduril/resources/oauth2/OAuth2Client.java new file mode 100644 index 00000000..5da96057 --- /dev/null +++ b/src/main/java/com/anduril/resources/oauth2/OAuth2Client.java @@ -0,0 +1,41 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.resources.oauth2; + +import com.anduril.core.ClientOptions; +import com.anduril.core.RequestOptions; +import com.anduril.resources.oauth2.requests.GetTokenRequest; +import com.anduril.resources.oauth2.types.GetTokenResponse; + +public class OAuth2Client { + protected final ClientOptions clientOptions; + + private final RawOAuth2Client rawClient; + + public OAuth2Client(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.rawClient = new RawOAuth2Client(clientOptions); + } + + /** + * Get responses with HTTP metadata like headers + */ + public RawOAuth2Client withRawResponse() { + return this.rawClient; + } + + /** + * Support the client credentials authorization flow + */ + public GetTokenResponse getToken(GetTokenRequest request) { + return this.rawClient.getToken(request).body(); + } + + /** + * Support the client credentials authorization flow + */ + public GetTokenResponse getToken(GetTokenRequest request, RequestOptions requestOptions) { + return this.rawClient.getToken(request, requestOptions).body(); + } +} diff --git a/src/main/java/com/anduril/resources/oauth2/RawOAuth2Client.java b/src/main/java/com/anduril/resources/oauth2/RawOAuth2Client.java new file mode 100644 index 00000000..1f221ed8 --- /dev/null +++ b/src/main/java/com/anduril/resources/oauth2/RawOAuth2Client.java @@ -0,0 +1,99 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.resources.oauth2; + +import com.anduril.core.ClientOptions; +import com.anduril.core.LatticeApiException; +import com.anduril.core.LatticeException; +import com.anduril.core.LatticeHttpResponse; +import com.anduril.core.ObjectMappers; +import com.anduril.core.RequestOptions; +import com.anduril.errors.BadRequestError; +import com.anduril.errors.UnauthorizedError; +import com.anduril.resources.oauth2.requests.GetTokenRequest; +import com.anduril.resources.oauth2.types.GetTokenResponse; +import com.fasterxml.jackson.core.JsonProcessingException; +import java.io.IOException; +import okhttp3.FormBody; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; + +public class RawOAuth2Client { + protected final ClientOptions clientOptions; + + public RawOAuth2Client(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + /** + * Support the client credentials authorization flow + */ + public LatticeHttpResponse getToken(GetTokenRequest request) { + return getToken(request, null); + } + + /** + * Support the client credentials authorization flow + */ + public LatticeHttpResponse getToken(GetTokenRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("api/v1/oauth/token") + .build(); + FormBody.Builder body = new FormBody.Builder(); + try { + body.add("grant_type", String.valueOf(request.getGrantType())); + if (request.getClientId().isPresent()) { + body.add("client_id", String.valueOf(request.getClientId().get())); + } + if (request.getClientSecret().isPresent()) { + body.add( + "client_secret", + String.valueOf(request.getClientSecret().get())); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + Request.Builder _requestBuilder = new Request.Builder() + .url(httpUrl) + .method("POST", body.build()) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/x-www-form-urlencoded") + .addHeader("Accept", "application/json"); + Request okhttpRequest = _requestBuilder.build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + return new LatticeHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, GetTokenResponse.class), response); + } + try { + switch (response.code()) { + case 400: + throw new BadRequestError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + case 401: + throw new UnauthorizedError( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class), response); + } + } catch (JsonProcessingException ignored) { + // unable to map error response, throwing generic error + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new LatticeApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (IOException e) { + throw new LatticeException("Network error executing HTTP request", e); + } + } +} diff --git a/src/main/java/com/anduril/resources/oauth2/requests/GetTokenRequest.java b/src/main/java/com/anduril/resources/oauth2/requests/GetTokenRequest.java new file mode 100644 index 00000000..11e17588 --- /dev/null +++ b/src/main/java/com/anduril/resources/oauth2/requests/GetTokenRequest.java @@ -0,0 +1,138 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.resources.oauth2.requests; + +import com.anduril.core.ObjectMappers; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = GetTokenRequest.Builder.class) +public final class GetTokenRequest { + private final Optional clientId; + + private final Optional clientSecret; + + private final Map additionalProperties; + + private GetTokenRequest( + Optional clientId, Optional clientSecret, Map additionalProperties) { + this.clientId = clientId; + this.clientSecret = clientSecret; + this.additionalProperties = additionalProperties; + } + + /** + * @return The type of grant being requested + */ + @JsonProperty("grant_type") + public String getGrantType() { + return "client_credentials"; + } + + /** + * @return The client identifier + */ + @JsonProperty("client_id") + public Optional getClientId() { + return clientId; + } + + /** + * @return The client secret + */ + @JsonProperty("client_secret") + public Optional getClientSecret() { + return clientSecret; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof GetTokenRequest && equalTo((GetTokenRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(GetTokenRequest other) { + return clientId.equals(other.clientId) && clientSecret.equals(other.clientSecret); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.clientId, this.clientSecret); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional clientId = Optional.empty(); + + private Optional clientSecret = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(GetTokenRequest other) { + clientId(other.getClientId()); + clientSecret(other.getClientSecret()); + return this; + } + + /** + *

The client identifier

+ */ + @JsonSetter(value = "client_id", nulls = Nulls.SKIP) + public Builder clientId(Optional clientId) { + this.clientId = clientId; + return this; + } + + public Builder clientId(String clientId) { + this.clientId = Optional.ofNullable(clientId); + return this; + } + + /** + *

The client secret

+ */ + @JsonSetter(value = "client_secret", nulls = Nulls.SKIP) + public Builder clientSecret(Optional clientSecret) { + this.clientSecret = clientSecret; + return this; + } + + public Builder clientSecret(String clientSecret) { + this.clientSecret = Optional.ofNullable(clientSecret); + return this; + } + + public GetTokenRequest build() { + return new GetTokenRequest(clientId, clientSecret, additionalProperties); + } + } +} diff --git a/src/main/java/com/anduril/resources/oauth2/types/GetTokenResponse.java b/src/main/java/com/anduril/resources/oauth2/types/GetTokenResponse.java new file mode 100644 index 00000000..1c52a01c --- /dev/null +++ b/src/main/java/com/anduril/resources/oauth2/types/GetTokenResponse.java @@ -0,0 +1,331 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.resources.oauth2.types; + +import com.anduril.core.ObjectMappers; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = GetTokenResponse.Builder.class) +public final class GetTokenResponse { + private final String accessToken; + + private final String tokenType; + + private final Optional expiresIn; + + private final Optional refreshExpiresIn; + + private final Optional notBeforePolicy; + + private final Optional scope; + + private final Map additionalProperties; + + private GetTokenResponse( + String accessToken, + String tokenType, + Optional expiresIn, + Optional refreshExpiresIn, + Optional notBeforePolicy, + Optional scope, + Map additionalProperties) { + this.accessToken = accessToken; + this.tokenType = tokenType; + this.expiresIn = expiresIn; + this.refreshExpiresIn = refreshExpiresIn; + this.notBeforePolicy = notBeforePolicy; + this.scope = scope; + this.additionalProperties = additionalProperties; + } + + /** + * @return The access token + */ + @JsonProperty("access_token") + public String getAccessToken() { + return accessToken; + } + + /** + * @return The type of token (typically "Bearer") + */ + @JsonProperty("token_type") + public String getTokenType() { + return tokenType; + } + + /** + * @return Lifetime of the access token in seconds + */ + @JsonProperty("expires_in") + public Optional getExpiresIn() { + return expiresIn; + } + + /** + * @return Lifetime of the refresh token + */ + @JsonProperty("refresh_expires_in") + public Optional getRefreshExpiresIn() { + return refreshExpiresIn; + } + + /** + * @return Enforce that a token cannot be used before a specific unixtime + */ + @JsonProperty("not-before-policy") + public Optional getNotBeforePolicy() { + return notBeforePolicy; + } + + /** + * @return The scope of the access token + */ + @JsonProperty("scope") + public Optional getScope() { + return scope; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof GetTokenResponse && equalTo((GetTokenResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(GetTokenResponse other) { + return accessToken.equals(other.accessToken) + && tokenType.equals(other.tokenType) + && expiresIn.equals(other.expiresIn) + && refreshExpiresIn.equals(other.refreshExpiresIn) + && notBeforePolicy.equals(other.notBeforePolicy) + && scope.equals(other.scope); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash( + this.accessToken, + this.tokenType, + this.expiresIn, + this.refreshExpiresIn, + this.notBeforePolicy, + this.scope); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static AccessTokenStage builder() { + return new Builder(); + } + + public interface AccessTokenStage { + /** + *

The access token

+ */ + TokenTypeStage accessToken(@NotNull String accessToken); + + Builder from(GetTokenResponse other); + } + + public interface TokenTypeStage { + /** + *

The type of token (typically "Bearer")

+ */ + _FinalStage tokenType(@NotNull String tokenType); + } + + public interface _FinalStage { + GetTokenResponse build(); + + /** + *

Lifetime of the access token in seconds

+ */ + _FinalStage expiresIn(Optional expiresIn); + + _FinalStage expiresIn(Integer expiresIn); + + /** + *

Lifetime of the refresh token

+ */ + _FinalStage refreshExpiresIn(Optional refreshExpiresIn); + + _FinalStage refreshExpiresIn(Integer refreshExpiresIn); + + /** + *

Enforce that a token cannot be used before a specific unixtime

+ */ + _FinalStage notBeforePolicy(Optional notBeforePolicy); + + _FinalStage notBeforePolicy(Integer notBeforePolicy); + + /** + *

The scope of the access token

+ */ + _FinalStage scope(Optional scope); + + _FinalStage scope(String scope); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements AccessTokenStage, TokenTypeStage, _FinalStage { + private String accessToken; + + private String tokenType; + + private Optional scope = Optional.empty(); + + private Optional notBeforePolicy = Optional.empty(); + + private Optional refreshExpiresIn = Optional.empty(); + + private Optional expiresIn = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(GetTokenResponse other) { + accessToken(other.getAccessToken()); + tokenType(other.getTokenType()); + expiresIn(other.getExpiresIn()); + refreshExpiresIn(other.getRefreshExpiresIn()); + notBeforePolicy(other.getNotBeforePolicy()); + scope(other.getScope()); + return this; + } + + /** + *

The access token

+ *

The access token

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("access_token") + public TokenTypeStage accessToken(@NotNull String accessToken) { + this.accessToken = Objects.requireNonNull(accessToken, "accessToken must not be null"); + return this; + } + + /** + *

The type of token (typically "Bearer")

+ *

The type of token (typically "Bearer")

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + @JsonSetter("token_type") + public _FinalStage tokenType(@NotNull String tokenType) { + this.tokenType = Objects.requireNonNull(tokenType, "tokenType must not be null"); + return this; + } + + /** + *

The scope of the access token

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage scope(String scope) { + this.scope = Optional.ofNullable(scope); + return this; + } + + /** + *

The scope of the access token

+ */ + @java.lang.Override + @JsonSetter(value = "scope", nulls = Nulls.SKIP) + public _FinalStage scope(Optional scope) { + this.scope = scope; + return this; + } + + /** + *

Enforce that a token cannot be used before a specific unixtime

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage notBeforePolicy(Integer notBeforePolicy) { + this.notBeforePolicy = Optional.ofNullable(notBeforePolicy); + return this; + } + + /** + *

Enforce that a token cannot be used before a specific unixtime

+ */ + @java.lang.Override + @JsonSetter(value = "not-before-policy", nulls = Nulls.SKIP) + public _FinalStage notBeforePolicy(Optional notBeforePolicy) { + this.notBeforePolicy = notBeforePolicy; + return this; + } + + /** + *

Lifetime of the refresh token

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage refreshExpiresIn(Integer refreshExpiresIn) { + this.refreshExpiresIn = Optional.ofNullable(refreshExpiresIn); + return this; + } + + /** + *

Lifetime of the refresh token

+ */ + @java.lang.Override + @JsonSetter(value = "refresh_expires_in", nulls = Nulls.SKIP) + public _FinalStage refreshExpiresIn(Optional refreshExpiresIn) { + this.refreshExpiresIn = refreshExpiresIn; + return this; + } + + /** + *

Lifetime of the access token in seconds

+ * @return Reference to {@code this} so that method calls can be chained together. + */ + @java.lang.Override + public _FinalStage expiresIn(Integer expiresIn) { + this.expiresIn = Optional.ofNullable(expiresIn); + return this; + } + + /** + *

Lifetime of the access token in seconds

+ */ + @java.lang.Override + @JsonSetter(value = "expires_in", nulls = Nulls.SKIP) + public _FinalStage expiresIn(Optional expiresIn) { + this.expiresIn = expiresIn; + return this; + } + + @java.lang.Override + public GetTokenResponse build() { + return new GetTokenResponse( + accessToken, tokenType, expiresIn, refreshExpiresIn, notBeforePolicy, scope, additionalProperties); + } + } +} diff --git a/src/main/java/com/anduril/resources/objects/AsyncObjectsClient.java b/src/main/java/com/anduril/resources/objects/AsyncObjectsClient.java index f900111b..c1ab4eac 100644 --- a/src/main/java/com/anduril/resources/objects/AsyncObjectsClient.java +++ b/src/main/java/com/anduril/resources/objects/AsyncObjectsClient.java @@ -38,6 +38,13 @@ public CompletableFuture> listObjects() { return this.rawClient.listObjects().thenApply(response -> response.body()); } + /** + * Lists objects in your environment. You can define a prefix to list a subset of your objects. If you do not set a prefix, Lattice returns all available objects. By default this endpoint will list local objects only. + */ + public CompletableFuture> listObjects(RequestOptions requestOptions) { + return this.rawClient.listObjects(requestOptions).thenApply(response -> response.body()); + } + /** * Lists objects in your environment. You can define a prefix to list a subset of your objects. If you do not set a prefix, Lattice returns all available objects. By default this endpoint will list local objects only. */ @@ -60,6 +67,13 @@ public CompletableFuture getObject(String objectPath) { return this.rawClient.getObject(objectPath).thenApply(response -> response.body()); } + /** + * Fetches an object from your environment using the objectPath path parameter. + */ + public CompletableFuture getObject(String objectPath, RequestOptions requestOptions) { + return this.rawClient.getObject(objectPath, requestOptions).thenApply(response -> response.body()); + } + /** * Fetches an object from your environment using the objectPath path parameter. */ @@ -112,6 +126,13 @@ public CompletableFuture deleteObject(String objectPath) { return this.rawClient.deleteObject(objectPath).thenApply(response -> response.body()); } + /** + * Deletes an object from your environment given the objectPath path parameter. + */ + public CompletableFuture deleteObject(String objectPath, RequestOptions requestOptions) { + return this.rawClient.deleteObject(objectPath, requestOptions).thenApply(response -> response.body()); + } + /** * Deletes an object from your environment given the objectPath path parameter. */ @@ -134,6 +155,13 @@ public CompletableFuture getObjectMetadata(String objectPath) { return this.rawClient.getObjectMetadata(objectPath).thenApply(response -> response.body()); } + /** + * Returns metadata for a specified object path. Use this to fetch metadata such as object size (size_bytes), its expiry time (expiry_time), or its latest update timestamp (last_updated_at). + */ + public CompletableFuture getObjectMetadata(String objectPath, RequestOptions requestOptions) { + return this.rawClient.getObjectMetadata(objectPath, requestOptions).thenApply(response -> response.body()); + } + /** * Returns metadata for a specified object path. Use this to fetch metadata such as object size (size_bytes), its expiry time (expiry_time), or its latest update timestamp (last_updated_at). */ diff --git a/src/main/java/com/anduril/resources/objects/AsyncRawObjectsClient.java b/src/main/java/com/anduril/resources/objects/AsyncRawObjectsClient.java index 472e28a3..73e1f001 100644 --- a/src/main/java/com/anduril/resources/objects/AsyncRawObjectsClient.java +++ b/src/main/java/com/anduril/resources/objects/AsyncRawObjectsClient.java @@ -59,6 +59,14 @@ public CompletableFuture>> return listObjects(ListObjectsRequest.builder().build()); } + /** + * Lists objects in your environment. You can define a prefix to list a subset of your objects. If you do not set a prefix, Lattice returns all available objects. By default this endpoint will list local objects only. + */ + public CompletableFuture>> listObjects( + RequestOptions requestOptions) { + return listObjects(ListObjectsRequest.builder().build(), requestOptions); + } + /** * Lists objects in your environment. You can define a prefix to list a subset of your objects. If you do not set a prefix, Lattice returns all available objects. By default this endpoint will list local objects only. */ @@ -175,6 +183,14 @@ public CompletableFuture> getObject(String obje return getObject(objectPath, GetObjectRequest.builder().build()); } + /** + * Fetches an object from your environment using the objectPath path parameter. + */ + public CompletableFuture> getObject( + String objectPath, RequestOptions requestOptions) { + return getObject(objectPath, GetObjectRequest.builder().build(), requestOptions); + } + /** * Fetches an object from your environment using the objectPath path parameter. */ @@ -199,10 +215,10 @@ public CompletableFuture> getObject( .addHeader("Accept", "application/json"); if (request.getAcceptEncoding().isPresent()) { _requestBuilder.addHeader( - "acceptEncoding", request.getAcceptEncoding().get().toString()); + "Accept-Encoding", request.getAcceptEncoding().get().toString()); } if (request.getPriority().isPresent()) { - _requestBuilder.addHeader("priority", request.getPriority().get()); + _requestBuilder.addHeader("Priority", request.getPriority().get()); } Request okhttpRequest = _requestBuilder.build(); OkHttpClient client = clientOptions.httpClient(); @@ -371,6 +387,13 @@ public CompletableFuture> deleteObject(String objectPa return deleteObject(objectPath, DeleteObjectRequest.builder().build()); } + /** + * Deletes an object from your environment given the objectPath path parameter. + */ + public CompletableFuture> deleteObject(String objectPath, RequestOptions requestOptions) { + return deleteObject(objectPath, DeleteObjectRequest.builder().build(), requestOptions); + } + /** * Deletes an object from your environment given the objectPath path parameter. */ @@ -458,6 +481,14 @@ public CompletableFuture> getObjectMetadata(String obj return getObjectMetadata(objectPath, GetObjectMetadataRequest.builder().build()); } + /** + * Returns metadata for a specified object path. Use this to fetch metadata such as object size (size_bytes), its expiry time (expiry_time), or its latest update timestamp (last_updated_at). + */ + public CompletableFuture> getObjectMetadata( + String objectPath, RequestOptions requestOptions) { + return getObjectMetadata(objectPath, GetObjectMetadataRequest.builder().build(), requestOptions); + } + /** * Returns metadata for a specified object path. Use this to fetch metadata such as object size (size_bytes), its expiry time (expiry_time), or its latest update timestamp (last_updated_at). */ diff --git a/src/main/java/com/anduril/resources/objects/ObjectsClient.java b/src/main/java/com/anduril/resources/objects/ObjectsClient.java index ae9636b0..0237c1ef 100644 --- a/src/main/java/com/anduril/resources/objects/ObjectsClient.java +++ b/src/main/java/com/anduril/resources/objects/ObjectsClient.java @@ -37,6 +37,13 @@ public SyncPagingIterable listObjects() { return this.rawClient.listObjects().body(); } + /** + * Lists objects in your environment. You can define a prefix to list a subset of your objects. If you do not set a prefix, Lattice returns all available objects. By default this endpoint will list local objects only. + */ + public SyncPagingIterable listObjects(RequestOptions requestOptions) { + return this.rawClient.listObjects(requestOptions).body(); + } + /** * Lists objects in your environment. You can define a prefix to list a subset of your objects. If you do not set a prefix, Lattice returns all available objects. By default this endpoint will list local objects only. */ @@ -58,6 +65,13 @@ public InputStream getObject(String objectPath) { return this.rawClient.getObject(objectPath).body(); } + /** + * Fetches an object from your environment using the objectPath path parameter. + */ + public InputStream getObject(String objectPath, RequestOptions requestOptions) { + return this.rawClient.getObject(objectPath, requestOptions).body(); + } + /** * Fetches an object from your environment using the objectPath path parameter. */ @@ -107,6 +121,13 @@ public void deleteObject(String objectPath) { this.rawClient.deleteObject(objectPath).body(); } + /** + * Deletes an object from your environment given the objectPath path parameter. + */ + public void deleteObject(String objectPath, RequestOptions requestOptions) { + this.rawClient.deleteObject(objectPath, requestOptions).body(); + } + /** * Deletes an object from your environment given the objectPath path parameter. */ @@ -128,6 +149,13 @@ public void getObjectMetadata(String objectPath) { this.rawClient.getObjectMetadata(objectPath).body(); } + /** + * Returns metadata for a specified object path. Use this to fetch metadata such as object size (size_bytes), its expiry time (expiry_time), or its latest update timestamp (last_updated_at). + */ + public void getObjectMetadata(String objectPath, RequestOptions requestOptions) { + this.rawClient.getObjectMetadata(objectPath, requestOptions).body(); + } + /** * Returns metadata for a specified object path. Use this to fetch metadata such as object size (size_bytes), its expiry time (expiry_time), or its latest update timestamp (last_updated_at). */ diff --git a/src/main/java/com/anduril/resources/objects/RawObjectsClient.java b/src/main/java/com/anduril/resources/objects/RawObjectsClient.java index 48a14d03..290e4680 100644 --- a/src/main/java/com/anduril/resources/objects/RawObjectsClient.java +++ b/src/main/java/com/anduril/resources/objects/RawObjectsClient.java @@ -54,6 +54,13 @@ public LatticeHttpResponse> listObjects() { return listObjects(ListObjectsRequest.builder().build()); } + /** + * Lists objects in your environment. You can define a prefix to list a subset of your objects. If you do not set a prefix, Lattice returns all available objects. By default this endpoint will list local objects only. + */ + public LatticeHttpResponse> listObjects(RequestOptions requestOptions) { + return listObjects(ListObjectsRequest.builder().build(), requestOptions); + } + /** * Lists objects in your environment. You can define a prefix to list a subset of your objects. If you do not set a prefix, Lattice returns all available objects. By default this endpoint will list local objects only. */ @@ -144,6 +151,13 @@ public LatticeHttpResponse getObject(String objectPath) { return getObject(objectPath, GetObjectRequest.builder().build()); } + /** + * Fetches an object from your environment using the objectPath path parameter. + */ + public LatticeHttpResponse getObject(String objectPath, RequestOptions requestOptions) { + return getObject(objectPath, GetObjectRequest.builder().build(), requestOptions); + } + /** * Fetches an object from your environment using the objectPath path parameter. */ @@ -168,10 +182,10 @@ public LatticeHttpResponse getObject( .addHeader("Accept", "application/json"); if (request.getAcceptEncoding().isPresent()) { _requestBuilder.addHeader( - "acceptEncoding", request.getAcceptEncoding().get().toString()); + "Accept-Encoding", request.getAcceptEncoding().get().toString()); } if (request.getPriority().isPresent()) { - _requestBuilder.addHeader("priority", request.getPriority().get()); + _requestBuilder.addHeader("Priority", request.getPriority().get()); } Request okhttpRequest = _requestBuilder.build(); OkHttpClient client = clientOptions.httpClient(); @@ -296,6 +310,13 @@ public LatticeHttpResponse deleteObject(String objectPath) { return deleteObject(objectPath, DeleteObjectRequest.builder().build()); } + /** + * Deletes an object from your environment given the objectPath path parameter. + */ + public LatticeHttpResponse deleteObject(String objectPath, RequestOptions requestOptions) { + return deleteObject(objectPath, DeleteObjectRequest.builder().build(), requestOptions); + } + /** * Deletes an object from your environment given the objectPath path parameter. */ @@ -362,6 +383,13 @@ public LatticeHttpResponse getObjectMetadata(String objectPath) { return getObjectMetadata(objectPath, GetObjectMetadataRequest.builder().build()); } + /** + * Returns metadata for a specified object path. Use this to fetch metadata such as object size (size_bytes), its expiry time (expiry_time), or its latest update timestamp (last_updated_at). + */ + public LatticeHttpResponse getObjectMetadata(String objectPath, RequestOptions requestOptions) { + return getObjectMetadata(objectPath, GetObjectMetadataRequest.builder().build(), requestOptions); + } + /** * Returns metadata for a specified object path. Use this to fetch metadata such as object size (size_bytes), its expiry time (expiry_time), or its latest update timestamp (last_updated_at). */ diff --git a/src/main/java/com/anduril/resources/tasks/AsyncRawTasksClient.java b/src/main/java/com/anduril/resources/tasks/AsyncRawTasksClient.java index 29b2190d..84bbf6a2 100644 --- a/src/main/java/com/anduril/resources/tasks/AsyncRawTasksClient.java +++ b/src/main/java/com/anduril/resources/tasks/AsyncRawTasksClient.java @@ -54,6 +54,18 @@ public CompletableFuture> createTask() { return createTask(TaskCreation.builder().build()); } + /** + * Creates a new Task in the system with the specified parameters. + *

This method initiates a new task with a unique ID (either provided or auto-generated), + * sets the initial task state to STATUS_CREATED, and establishes task ownership. The task + * can be assigned to a specific agent through the Relations field.

+ *

Once created, a task enters the lifecycle workflow and can be tracked, updated, and managed + * through other Tasks API endpoints.

+ */ + public CompletableFuture> createTask(RequestOptions requestOptions) { + return createTask(TaskCreation.builder().build(), requestOptions); + } + /** * Creates a new Task in the system with the specified parameters. *

This method initiates a new task with a unique ID (either provided or auto-generated), @@ -154,6 +166,18 @@ public CompletableFuture> getTask(String taskId) { return getTask(taskId, GetTaskRequest.builder().build()); } + /** + * Retrieves a specific Task by its ID, with options to select a particular task version or view. + *

This method returns detailed information about a task including its current status, + * specification, relations, and other metadata. The response includes the complete Task object + * with all associated fields.

+ *

By default, the method returns the latest definition version of the task from the manager's + * perspective.

+ */ + public CompletableFuture> getTask(String taskId, RequestOptions requestOptions) { + return getTask(taskId, GetTaskRequest.builder().build(), requestOptions); + } + /** * Retrieves a specific Task by its ID, with options to select a particular task version or view. *

This method returns detailed information about a task including its current status, @@ -254,6 +278,20 @@ public CompletableFuture> updateTaskStatus(String task return updateTaskStatus(taskId, TaskStatusUpdate.builder().build()); } + /** + * Updates the status of a Task as it progresses through its lifecycle. + *

This method allows agents or operators to report the current state of a task, + * which could include changes to task status, and error information.

+ *

Each status update increments the task's status_version. When updating status, + * clients must provide the current version to ensure consistency. The system rejects + * updates with mismatched versions to prevent race conditions.

+ *

Terminal states (STATUS_DONE_OK and STATUS_DONE_NOT_OK) are permanent; once a task + * reaches these states, no further updates are allowed.

+ */ + public CompletableFuture> updateTaskStatus(String taskId, RequestOptions requestOptions) { + return updateTaskStatus(taskId, TaskStatusUpdate.builder().build(), requestOptions); + } + /** * Updates the status of a Task as it progresses through its lifecycle. *

This method allows agents or operators to report the current state of a task, @@ -373,6 +411,26 @@ public CompletableFuture> queryTasks() { return queryTasks(TaskQuery.builder().build()); } + /** + * Searches for Tasks that match specified filtering criteria and returns matching tasks in paginated form. + *

This method allows filtering tasks based on multiple criteria including:

+ *
    + *
  • Parent task relationships
  • + *
  • Task status (with inclusive or exclusive filtering)
  • + *
  • Update time ranges
  • + *
  • Task view (manager or agent perspective)
  • + *
  • Task assignee
  • + *
  • Task type (via exact URL matches or prefix matching)
  • + *
+ *

Results are returned in pages. When more results are available than can be returned in a single + * response, a page_token is provided that can be used in subsequent requests to retrieve the next + * set of results.

+ *

By default, this returns the latest task version for each matching task from the manager's perspective.

+ */ + public CompletableFuture> queryTasks(RequestOptions requestOptions) { + return queryTasks(TaskQuery.builder().build(), requestOptions); + } + /** * Searches for Tasks that match specified filtering criteria and returns matching tasks in paginated form. *

This method allows filtering tasks based on multiple criteria including:

@@ -506,6 +564,29 @@ public CompletableFuture> listenAsAgent() { return listenAsAgent(AgentListener.builder().build()); } + /** + * Establishes a server streaming connection that delivers tasks to taskable agents for execution. + *

This method creates a persistent connection from Tasks API to an agent, allowing the server + * to push tasks to the agent as they become available. The agent receives a stream of tasks that + * match its selector criteria (entity IDs).

+ *

The stream delivers three types of requests:

+ *
    + *
  • ExecuteRequest: Contains a new task for the agent to execute
  • + *
  • CancelRequest: Indicates a task should be canceled
  • + *
  • CompleteRequest: Indicates a task should be completed
  • + *
+ *

This is the primary method for taskable agents to receive and process tasks in real-time. + * Agents should maintain this connection and process incoming tasks according to their capabilities.

+ *

When an agent receives a task, it should update the task status using the UpdateStatus endpoint + * to provide progress information back to Tasks API.

+ *

This is a long polling API that will block until a new task is ready for delivery. If no new task is + * available then the server will hold on to your request for up to 5 minutes, after that 5 minute timeout + * period you will be expected to reinitiate a new request.

+ */ + public CompletableFuture> listenAsAgent(RequestOptions requestOptions) { + return listenAsAgent(AgentListener.builder().build(), requestOptions); + } + /** * Establishes a server streaming connection that delivers tasks to taskable agents for execution. *

This method creates a persistent connection from Tasks API to an agent, allowing the server diff --git a/src/main/java/com/anduril/resources/tasks/AsyncTasksClient.java b/src/main/java/com/anduril/resources/tasks/AsyncTasksClient.java index 075a5c2e..5305bdfc 100644 --- a/src/main/java/com/anduril/resources/tasks/AsyncTasksClient.java +++ b/src/main/java/com/anduril/resources/tasks/AsyncTasksClient.java @@ -44,6 +44,18 @@ public CompletableFuture createTask() { return this.rawClient.createTask().thenApply(response -> response.body()); } + /** + * Creates a new Task in the system with the specified parameters. + *

This method initiates a new task with a unique ID (either provided or auto-generated), + * sets the initial task state to STATUS_CREATED, and establishes task ownership. The task + * can be assigned to a specific agent through the Relations field.

+ *

Once created, a task enters the lifecycle workflow and can be tracked, updated, and managed + * through other Tasks API endpoints.

+ */ + public CompletableFuture createTask(RequestOptions requestOptions) { + return this.rawClient.createTask(requestOptions).thenApply(response -> response.body()); + } + /** * Creates a new Task in the system with the specified parameters. *

This method initiates a new task with a unique ID (either provided or auto-generated), @@ -80,6 +92,18 @@ public CompletableFuture getTask(String taskId) { return this.rawClient.getTask(taskId).thenApply(response -> response.body()); } + /** + * Retrieves a specific Task by its ID, with options to select a particular task version or view. + *

This method returns detailed information about a task including its current status, + * specification, relations, and other metadata. The response includes the complete Task object + * with all associated fields.

+ *

By default, the method returns the latest definition version of the task from the manager's + * perspective.

+ */ + public CompletableFuture getTask(String taskId, RequestOptions requestOptions) { + return this.rawClient.getTask(taskId, requestOptions).thenApply(response -> response.body()); + } + /** * Retrieves a specific Task by its ID, with options to select a particular task version or view. *

This method returns detailed information about a task including its current status, @@ -118,6 +142,20 @@ public CompletableFuture updateTaskStatus(String taskId) { return this.rawClient.updateTaskStatus(taskId).thenApply(response -> response.body()); } + /** + * Updates the status of a Task as it progresses through its lifecycle. + *

This method allows agents or operators to report the current state of a task, + * which could include changes to task status, and error information.

+ *

Each status update increments the task's status_version. When updating status, + * clients must provide the current version to ensure consistency. The system rejects + * updates with mismatched versions to prevent race conditions.

+ *

Terminal states (STATUS_DONE_OK and STATUS_DONE_NOT_OK) are permanent; once a task + * reaches these states, no further updates are allowed.

+ */ + public CompletableFuture updateTaskStatus(String taskId, RequestOptions requestOptions) { + return this.rawClient.updateTaskStatus(taskId, requestOptions).thenApply(response -> response.body()); + } + /** * Updates the status of a Task as it progresses through its lifecycle. *

This method allows agents or operators to report the current state of a task, @@ -167,6 +205,26 @@ public CompletableFuture queryTasks() { return this.rawClient.queryTasks().thenApply(response -> response.body()); } + /** + * Searches for Tasks that match specified filtering criteria and returns matching tasks in paginated form. + *

This method allows filtering tasks based on multiple criteria including:

+ *
    + *
  • Parent task relationships
  • + *
  • Task status (with inclusive or exclusive filtering)
  • + *
  • Update time ranges
  • + *
  • Task view (manager or agent perspective)
  • + *
  • Task assignee
  • + *
  • Task type (via exact URL matches or prefix matching)
  • + *
+ *

Results are returned in pages. When more results are available than can be returned in a single + * response, a page_token is provided that can be used in subsequent requests to retrieve the next + * set of results.

+ *

By default, this returns the latest task version for each matching task from the manager's perspective.

+ */ + public CompletableFuture queryTasks(RequestOptions requestOptions) { + return this.rawClient.queryTasks(requestOptions).thenApply(response -> response.body()); + } + /** * Searches for Tasks that match specified filtering criteria and returns matching tasks in paginated form. *

This method allows filtering tasks based on multiple criteria including:

@@ -230,6 +288,29 @@ public CompletableFuture listenAsAgent() { return this.rawClient.listenAsAgent().thenApply(response -> response.body()); } + /** + * Establishes a server streaming connection that delivers tasks to taskable agents for execution. + *

This method creates a persistent connection from Tasks API to an agent, allowing the server + * to push tasks to the agent as they become available. The agent receives a stream of tasks that + * match its selector criteria (entity IDs).

+ *

The stream delivers three types of requests:

+ *
    + *
  • ExecuteRequest: Contains a new task for the agent to execute
  • + *
  • CancelRequest: Indicates a task should be canceled
  • + *
  • CompleteRequest: Indicates a task should be completed
  • + *
+ *

This is the primary method for taskable agents to receive and process tasks in real-time. + * Agents should maintain this connection and process incoming tasks according to their capabilities.

+ *

When an agent receives a task, it should update the task status using the UpdateStatus endpoint + * to provide progress information back to Tasks API.

+ *

This is a long polling API that will block until a new task is ready for delivery. If no new task is + * available then the server will hold on to your request for up to 5 minutes, after that 5 minute timeout + * period you will be expected to reinitiate a new request.

+ */ + public CompletableFuture listenAsAgent(RequestOptions requestOptions) { + return this.rawClient.listenAsAgent(requestOptions).thenApply(response -> response.body()); + } + /** * Establishes a server streaming connection that delivers tasks to taskable agents for execution. *

This method creates a persistent connection from Tasks API to an agent, allowing the server diff --git a/src/main/java/com/anduril/resources/tasks/RawTasksClient.java b/src/main/java/com/anduril/resources/tasks/RawTasksClient.java index 26e6f983..50fca287 100644 --- a/src/main/java/com/anduril/resources/tasks/RawTasksClient.java +++ b/src/main/java/com/anduril/resources/tasks/RawTasksClient.java @@ -50,6 +50,18 @@ public LatticeHttpResponse createTask() { return createTask(TaskCreation.builder().build()); } + /** + * Creates a new Task in the system with the specified parameters. + *

This method initiates a new task with a unique ID (either provided or auto-generated), + * sets the initial task state to STATUS_CREATED, and establishes task ownership. The task + * can be assigned to a specific agent through the Relations field.

+ *

Once created, a task enters the lifecycle workflow and can be tracked, updated, and managed + * through other Tasks API endpoints.

+ */ + public LatticeHttpResponse createTask(RequestOptions requestOptions) { + return createTask(TaskCreation.builder().build(), requestOptions); + } + /** * Creates a new Task in the system with the specified parameters. *

This method initiates a new task with a unique ID (either provided or auto-generated), @@ -132,6 +144,18 @@ public LatticeHttpResponse getTask(String taskId) { return getTask(taskId, GetTaskRequest.builder().build()); } + /** + * Retrieves a specific Task by its ID, with options to select a particular task version or view. + *

This method returns detailed information about a task including its current status, + * specification, relations, and other metadata. The response includes the complete Task object + * with all associated fields.

+ *

By default, the method returns the latest definition version of the task from the manager's + * perspective.

+ */ + public LatticeHttpResponse getTask(String taskId, RequestOptions requestOptions) { + return getTask(taskId, GetTaskRequest.builder().build(), requestOptions); + } + /** * Retrieves a specific Task by its ID, with options to select a particular task version or view. *

This method returns detailed information about a task including its current status, @@ -212,6 +236,20 @@ public LatticeHttpResponse updateTaskStatus(String taskId) { return updateTaskStatus(taskId, TaskStatusUpdate.builder().build()); } + /** + * Updates the status of a Task as it progresses through its lifecycle. + *

This method allows agents or operators to report the current state of a task, + * which could include changes to task status, and error information.

+ *

Each status update increments the task's status_version. When updating status, + * clients must provide the current version to ensure consistency. The system rejects + * updates with mismatched versions to prevent race conditions.

+ *

Terminal states (STATUS_DONE_OK and STATUS_DONE_NOT_OK) are permanent; once a task + * reaches these states, no further updates are allowed.

+ */ + public LatticeHttpResponse updateTaskStatus(String taskId, RequestOptions requestOptions) { + return updateTaskStatus(taskId, TaskStatusUpdate.builder().build(), requestOptions); + } + /** * Updates the status of a Task as it progresses through its lifecycle. *

This method allows agents or operators to report the current state of a task, @@ -312,6 +350,26 @@ public LatticeHttpResponse queryTasks() { return queryTasks(TaskQuery.builder().build()); } + /** + * Searches for Tasks that match specified filtering criteria and returns matching tasks in paginated form. + *

This method allows filtering tasks based on multiple criteria including:

+ *
    + *
  • Parent task relationships
  • + *
  • Task status (with inclusive or exclusive filtering)
  • + *
  • Update time ranges
  • + *
  • Task view (manager or agent perspective)
  • + *
  • Task assignee
  • + *
  • Task type (via exact URL matches or prefix matching)
  • + *
+ *

Results are returned in pages. When more results are available than can be returned in a single + * response, a page_token is provided that can be used in subsequent requests to retrieve the next + * set of results.

+ *

By default, this returns the latest task version for each matching task from the manager's perspective.

+ */ + public LatticeHttpResponse queryTasks(RequestOptions requestOptions) { + return queryTasks(TaskQuery.builder().build(), requestOptions); + } + /** * Searches for Tasks that match specified filtering criteria and returns matching tasks in paginated form. *

This method allows filtering tasks based on multiple criteria including:

@@ -424,6 +482,29 @@ public LatticeHttpResponse listenAsAgent() { return listenAsAgent(AgentListener.builder().build()); } + /** + * Establishes a server streaming connection that delivers tasks to taskable agents for execution. + *

This method creates a persistent connection from Tasks API to an agent, allowing the server + * to push tasks to the agent as they become available. The agent receives a stream of tasks that + * match its selector criteria (entity IDs).

+ *

The stream delivers three types of requests:

+ *
    + *
  • ExecuteRequest: Contains a new task for the agent to execute
  • + *
  • CancelRequest: Indicates a task should be canceled
  • + *
  • CompleteRequest: Indicates a task should be completed
  • + *
+ *

This is the primary method for taskable agents to receive and process tasks in real-time. + * Agents should maintain this connection and process incoming tasks according to their capabilities.

+ *

When an agent receives a task, it should update the task status using the UpdateStatus endpoint + * to provide progress information back to Tasks API.

+ *

This is a long polling API that will block until a new task is ready for delivery. If no new task is + * available then the server will hold on to your request for up to 5 minutes, after that 5 minute timeout + * period you will be expected to reinitiate a new request.

+ */ + public LatticeHttpResponse listenAsAgent(RequestOptions requestOptions) { + return listenAsAgent(AgentListener.builder().build(), requestOptions); + } + /** * Establishes a server streaming connection that delivers tasks to taskable agents for execution. *

This method creates a persistent connection from Tasks API to an agent, allowing the server diff --git a/src/main/java/com/anduril/resources/tasks/TasksClient.java b/src/main/java/com/anduril/resources/tasks/TasksClient.java index bbfa2e2e..32ac79ec 100644 --- a/src/main/java/com/anduril/resources/tasks/TasksClient.java +++ b/src/main/java/com/anduril/resources/tasks/TasksClient.java @@ -43,6 +43,18 @@ public Task createTask() { return this.rawClient.createTask().body(); } + /** + * Creates a new Task in the system with the specified parameters. + *

This method initiates a new task with a unique ID (either provided or auto-generated), + * sets the initial task state to STATUS_CREATED, and establishes task ownership. The task + * can be assigned to a specific agent through the Relations field.

+ *

Once created, a task enters the lifecycle workflow and can be tracked, updated, and managed + * through other Tasks API endpoints.

+ */ + public Task createTask(RequestOptions requestOptions) { + return this.rawClient.createTask(requestOptions).body(); + } + /** * Creates a new Task in the system with the specified parameters. *

This method initiates a new task with a unique ID (either provided or auto-generated), @@ -79,6 +91,18 @@ public Task getTask(String taskId) { return this.rawClient.getTask(taskId).body(); } + /** + * Retrieves a specific Task by its ID, with options to select a particular task version or view. + *

This method returns detailed information about a task including its current status, + * specification, relations, and other metadata. The response includes the complete Task object + * with all associated fields.

+ *

By default, the method returns the latest definition version of the task from the manager's + * perspective.

+ */ + public Task getTask(String taskId, RequestOptions requestOptions) { + return this.rawClient.getTask(taskId, requestOptions).body(); + } + /** * Retrieves a specific Task by its ID, with options to select a particular task version or view. *

This method returns detailed information about a task including its current status, @@ -117,6 +141,20 @@ public Task updateTaskStatus(String taskId) { return this.rawClient.updateTaskStatus(taskId).body(); } + /** + * Updates the status of a Task as it progresses through its lifecycle. + *

This method allows agents or operators to report the current state of a task, + * which could include changes to task status, and error information.

+ *

Each status update increments the task's status_version. When updating status, + * clients must provide the current version to ensure consistency. The system rejects + * updates with mismatched versions to prevent race conditions.

+ *

Terminal states (STATUS_DONE_OK and STATUS_DONE_NOT_OK) are permanent; once a task + * reaches these states, no further updates are allowed.

+ */ + public Task updateTaskStatus(String taskId, RequestOptions requestOptions) { + return this.rawClient.updateTaskStatus(taskId, requestOptions).body(); + } + /** * Updates the status of a Task as it progresses through its lifecycle. *

This method allows agents or operators to report the current state of a task, @@ -165,6 +203,26 @@ public TaskQueryResults queryTasks() { return this.rawClient.queryTasks().body(); } + /** + * Searches for Tasks that match specified filtering criteria and returns matching tasks in paginated form. + *

This method allows filtering tasks based on multiple criteria including:

+ *
    + *
  • Parent task relationships
  • + *
  • Task status (with inclusive or exclusive filtering)
  • + *
  • Update time ranges
  • + *
  • Task view (manager or agent perspective)
  • + *
  • Task assignee
  • + *
  • Task type (via exact URL matches or prefix matching)
  • + *
+ *

Results are returned in pages. When more results are available than can be returned in a single + * response, a page_token is provided that can be used in subsequent requests to retrieve the next + * set of results.

+ *

By default, this returns the latest task version for each matching task from the manager's perspective.

+ */ + public TaskQueryResults queryTasks(RequestOptions requestOptions) { + return this.rawClient.queryTasks(requestOptions).body(); + } + /** * Searches for Tasks that match specified filtering criteria and returns matching tasks in paginated form. *

This method allows filtering tasks based on multiple criteria including:

@@ -228,6 +286,29 @@ public AgentRequest listenAsAgent() { return this.rawClient.listenAsAgent().body(); } + /** + * Establishes a server streaming connection that delivers tasks to taskable agents for execution. + *

This method creates a persistent connection from Tasks API to an agent, allowing the server + * to push tasks to the agent as they become available. The agent receives a stream of tasks that + * match its selector criteria (entity IDs).

+ *

The stream delivers three types of requests:

+ *
    + *
  • ExecuteRequest: Contains a new task for the agent to execute
  • + *
  • CancelRequest: Indicates a task should be canceled
  • + *
  • CompleteRequest: Indicates a task should be completed
  • + *
+ *

This is the primary method for taskable agents to receive and process tasks in real-time. + * Agents should maintain this connection and process incoming tasks according to their capabilities.

+ *

When an agent receives a task, it should update the task status using the UpdateStatus endpoint + * to provide progress information back to Tasks API.

+ *

This is a long polling API that will block until a new task is ready for delivery. If no new task is + * available then the server will hold on to your request for up to 5 minutes, after that 5 minute timeout + * period you will be expected to reinitiate a new request.

+ */ + public AgentRequest listenAsAgent(RequestOptions requestOptions) { + return this.rawClient.listenAsAgent(requestOptions).body(); + } + /** * Establishes a server streaming connection that delivers tasks to taskable agents for execution. *

This method creates a persistent connection from Tasks API to an agent, allowing the server diff --git a/src/main/java/com/anduril/types/AgentStreamEvent.java b/src/main/java/com/anduril/types/AgentStreamEvent.java new file mode 100644 index 00000000..d7c84459 --- /dev/null +++ b/src/main/java/com/anduril/types/AgentStreamEvent.java @@ -0,0 +1,125 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.types; + +import com.anduril.core.ObjectMappers; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = AgentStreamEvent.Builder.class) +public final class AgentStreamEvent { + private final AgentStreamEventEvent event; + + private final AgentTaskRequest data; + + private final Map additionalProperties; + + private AgentStreamEvent( + AgentStreamEventEvent event, AgentTaskRequest data, Map additionalProperties) { + this.event = event; + this.data = data; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("event") + public AgentStreamEventEvent getEvent() { + return event; + } + + @JsonProperty("data") + public AgentTaskRequest getData() { + return data; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AgentStreamEvent && equalTo((AgentStreamEvent) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(AgentStreamEvent other) { + return event.equals(other.event) && data.equals(other.data); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.event, this.data); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static EventStage builder() { + return new Builder(); + } + + public interface EventStage { + DataStage event(@NotNull AgentStreamEventEvent event); + + Builder from(AgentStreamEvent other); + } + + public interface DataStage { + _FinalStage data(@NotNull AgentTaskRequest data); + } + + public interface _FinalStage { + AgentStreamEvent build(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements EventStage, DataStage, _FinalStage { + private AgentStreamEventEvent event; + + private AgentTaskRequest data; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(AgentStreamEvent other) { + event(other.getEvent()); + data(other.getData()); + return this; + } + + @java.lang.Override + @JsonSetter("event") + public DataStage event(@NotNull AgentStreamEventEvent event) { + this.event = Objects.requireNonNull(event, "event must not be null"); + return this; + } + + @java.lang.Override + @JsonSetter("data") + public _FinalStage data(@NotNull AgentTaskRequest data) { + this.data = Objects.requireNonNull(data, "data must not be null"); + return this; + } + + @java.lang.Override + public AgentStreamEvent build() { + return new AgentStreamEvent(event, data, additionalProperties); + } + } +} diff --git a/src/main/java/com/anduril/types/AgentStreamEventEvent.java b/src/main/java/com/anduril/types/AgentStreamEventEvent.java new file mode 100644 index 00000000..da282e20 --- /dev/null +++ b/src/main/java/com/anduril/types/AgentStreamEventEvent.java @@ -0,0 +1,75 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.types; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public final class AgentStreamEventEvent { + public static final AgentStreamEventEvent AGENT_REQUEST = + new AgentStreamEventEvent(Value.AGENT_REQUEST, "agent_request"); + + private final Value value; + + private final String string; + + AgentStreamEventEvent(Value value, String string) { + this.value = value; + this.string = string; + } + + public Value getEnumValue() { + return value; + } + + @java.lang.Override + @JsonValue + public String toString() { + return this.string; + } + + @java.lang.Override + public boolean equals(Object other) { + return (this == other) + || (other instanceof AgentStreamEventEvent + && this.string.equals(((AgentStreamEventEvent) other).string)); + } + + @java.lang.Override + public int hashCode() { + return this.string.hashCode(); + } + + public T visit(Visitor visitor) { + switch (value) { + case AGENT_REQUEST: + return visitor.visitAgentRequest(); + case UNKNOWN: + default: + return visitor.visitUnknown(string); + } + } + + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static AgentStreamEventEvent valueOf(String value) { + switch (value) { + case "agent_request": + return AGENT_REQUEST; + default: + return new AgentStreamEventEvent(Value.UNKNOWN, value); + } + } + + public enum Value { + AGENT_REQUEST, + + UNKNOWN + } + + public interface Visitor { + T visitAgentRequest(); + + T visitUnknown(String unknownType); + } +} diff --git a/src/main/java/com/anduril/types/AgentStreamHeartbeat.java b/src/main/java/com/anduril/types/AgentStreamHeartbeat.java new file mode 100644 index 00000000..a0dfb963 --- /dev/null +++ b/src/main/java/com/anduril/types/AgentStreamHeartbeat.java @@ -0,0 +1,125 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.types; + +import com.anduril.core.ObjectMappers; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = AgentStreamHeartbeat.Builder.class) +public final class AgentStreamHeartbeat { + private final AgentStreamHeartbeatEvent event; + + private final AgentStreamHeartbeatData data; + + private final Map additionalProperties; + + private AgentStreamHeartbeat( + AgentStreamHeartbeatEvent event, AgentStreamHeartbeatData data, Map additionalProperties) { + this.event = event; + this.data = data; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("event") + public AgentStreamHeartbeatEvent getEvent() { + return event; + } + + @JsonProperty("data") + public AgentStreamHeartbeatData getData() { + return data; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AgentStreamHeartbeat && equalTo((AgentStreamHeartbeat) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(AgentStreamHeartbeat other) { + return event.equals(other.event) && data.equals(other.data); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.event, this.data); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static EventStage builder() { + return new Builder(); + } + + public interface EventStage { + DataStage event(@NotNull AgentStreamHeartbeatEvent event); + + Builder from(AgentStreamHeartbeat other); + } + + public interface DataStage { + _FinalStage data(@NotNull AgentStreamHeartbeatData data); + } + + public interface _FinalStage { + AgentStreamHeartbeat build(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements EventStage, DataStage, _FinalStage { + private AgentStreamHeartbeatEvent event; + + private AgentStreamHeartbeatData data; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(AgentStreamHeartbeat other) { + event(other.getEvent()); + data(other.getData()); + return this; + } + + @java.lang.Override + @JsonSetter("event") + public DataStage event(@NotNull AgentStreamHeartbeatEvent event) { + this.event = Objects.requireNonNull(event, "event must not be null"); + return this; + } + + @java.lang.Override + @JsonSetter("data") + public _FinalStage data(@NotNull AgentStreamHeartbeatData data) { + this.data = Objects.requireNonNull(data, "data must not be null"); + return this; + } + + @java.lang.Override + public AgentStreamHeartbeat build() { + return new AgentStreamHeartbeat(event, data, additionalProperties); + } + } +} diff --git a/src/main/java/com/anduril/types/AgentStreamHeartbeatData.java b/src/main/java/com/anduril/types/AgentStreamHeartbeatData.java new file mode 100644 index 00000000..a1671d3e --- /dev/null +++ b/src/main/java/com/anduril/types/AgentStreamHeartbeatData.java @@ -0,0 +1,101 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.types; + +import com.anduril.core.ObjectMappers; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = AgentStreamHeartbeatData.Builder.class) +public final class AgentStreamHeartbeatData { + private final Optional timestamp; + + private final Map additionalProperties; + + private AgentStreamHeartbeatData(Optional timestamp, Map additionalProperties) { + this.timestamp = timestamp; + this.additionalProperties = additionalProperties; + } + + /** + * @return The timestamp at which the heartbeat message was sent. + */ + @JsonProperty("timestamp") + public Optional getTimestamp() { + return timestamp; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AgentStreamHeartbeatData && equalTo((AgentStreamHeartbeatData) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(AgentStreamHeartbeatData other) { + return timestamp.equals(other.timestamp); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.timestamp); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional timestamp = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(AgentStreamHeartbeatData other) { + timestamp(other.getTimestamp()); + return this; + } + + /** + *

The timestamp at which the heartbeat message was sent.

+ */ + @JsonSetter(value = "timestamp", nulls = Nulls.SKIP) + public Builder timestamp(Optional timestamp) { + this.timestamp = timestamp; + return this; + } + + public Builder timestamp(String timestamp) { + this.timestamp = Optional.ofNullable(timestamp); + return this; + } + + public AgentStreamHeartbeatData build() { + return new AgentStreamHeartbeatData(timestamp, additionalProperties); + } + } +} diff --git a/src/main/java/com/anduril/types/AgentStreamHeartbeatEvent.java b/src/main/java/com/anduril/types/AgentStreamHeartbeatEvent.java new file mode 100644 index 00000000..079c042e --- /dev/null +++ b/src/main/java/com/anduril/types/AgentStreamHeartbeatEvent.java @@ -0,0 +1,75 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.types; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public final class AgentStreamHeartbeatEvent { + public static final AgentStreamHeartbeatEvent HEARTBEAT = + new AgentStreamHeartbeatEvent(Value.HEARTBEAT, "heartbeat"); + + private final Value value; + + private final String string; + + AgentStreamHeartbeatEvent(Value value, String string) { + this.value = value; + this.string = string; + } + + public Value getEnumValue() { + return value; + } + + @java.lang.Override + @JsonValue + public String toString() { + return this.string; + } + + @java.lang.Override + public boolean equals(Object other) { + return (this == other) + || (other instanceof AgentStreamHeartbeatEvent + && this.string.equals(((AgentStreamHeartbeatEvent) other).string)); + } + + @java.lang.Override + public int hashCode() { + return this.string.hashCode(); + } + + public T visit(Visitor visitor) { + switch (value) { + case HEARTBEAT: + return visitor.visitHeartbeat(); + case UNKNOWN: + default: + return visitor.visitUnknown(string); + } + } + + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static AgentStreamHeartbeatEvent valueOf(String value) { + switch (value) { + case "heartbeat": + return HEARTBEAT; + default: + return new AgentStreamHeartbeatEvent(Value.UNKNOWN, value); + } + } + + public enum Value { + HEARTBEAT, + + UNKNOWN + } + + public interface Visitor { + T visitHeartbeat(); + + T visitUnknown(String unknownType); + } +} diff --git a/src/main/java/com/anduril/types/AgentStreamRequest.java b/src/main/java/com/anduril/types/AgentStreamRequest.java new file mode 100644 index 00000000..7e5a5295 --- /dev/null +++ b/src/main/java/com/anduril/types/AgentStreamRequest.java @@ -0,0 +1,132 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.types; + +import com.anduril.core.ObjectMappers; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = AgentStreamRequest.Builder.class) +public final class AgentStreamRequest { + private final Optional agentSelector; + + private final Optional heartbeatIntervalMs; + + private final Map additionalProperties; + + private AgentStreamRequest( + Optional agentSelector, + Optional heartbeatIntervalMs, + Map additionalProperties) { + this.agentSelector = agentSelector; + this.heartbeatIntervalMs = heartbeatIntervalMs; + this.additionalProperties = additionalProperties; + } + + /** + * @return The selector criteria to determine which tasks the agent receives. + */ + @JsonProperty("agentSelector") + public Optional getAgentSelector() { + return agentSelector; + } + + /** + * @return The time interval, defined in seconds, that determines the frequency at which to send heartbeat events. Defaults to 30s. + */ + @JsonProperty("heartbeatIntervalMs") + public Optional getHeartbeatIntervalMs() { + return heartbeatIntervalMs; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AgentStreamRequest && equalTo((AgentStreamRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(AgentStreamRequest other) { + return agentSelector.equals(other.agentSelector) && heartbeatIntervalMs.equals(other.heartbeatIntervalMs); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.agentSelector, this.heartbeatIntervalMs); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional agentSelector = Optional.empty(); + + private Optional heartbeatIntervalMs = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(AgentStreamRequest other) { + agentSelector(other.getAgentSelector()); + heartbeatIntervalMs(other.getHeartbeatIntervalMs()); + return this; + } + + /** + *

The selector criteria to determine which tasks the agent receives.

+ */ + @JsonSetter(value = "agentSelector", nulls = Nulls.SKIP) + public Builder agentSelector(Optional agentSelector) { + this.agentSelector = agentSelector; + return this; + } + + public Builder agentSelector(EntityIdsSelector agentSelector) { + this.agentSelector = Optional.ofNullable(agentSelector); + return this; + } + + /** + *

The time interval, defined in seconds, that determines the frequency at which to send heartbeat events. Defaults to 30s.

+ */ + @JsonSetter(value = "heartbeatIntervalMs", nulls = Nulls.SKIP) + public Builder heartbeatIntervalMs(Optional heartbeatIntervalMs) { + this.heartbeatIntervalMs = heartbeatIntervalMs; + return this; + } + + public Builder heartbeatIntervalMs(Integer heartbeatIntervalMs) { + this.heartbeatIntervalMs = Optional.ofNullable(heartbeatIntervalMs); + return this; + } + + public AgentStreamRequest build() { + return new AgentStreamRequest(agentSelector, heartbeatIntervalMs, additionalProperties); + } + } +} diff --git a/src/main/java/com/anduril/types/AgentTaskRequest.java b/src/main/java/com/anduril/types/AgentTaskRequest.java new file mode 100644 index 00000000..096fee8d --- /dev/null +++ b/src/main/java/com/anduril/types/AgentTaskRequest.java @@ -0,0 +1,145 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.types; + +import com.anduril.core.ObjectMappers; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = AgentTaskRequest.Builder.class) +public final class AgentTaskRequest { + private final Optional executeRequest; + + private final Optional cancelRequest; + + private final Optional completeRequest; + + private final Map additionalProperties; + + private AgentTaskRequest( + Optional executeRequest, + Optional cancelRequest, + Optional completeRequest, + Map additionalProperties) { + this.executeRequest = executeRequest; + this.cancelRequest = cancelRequest; + this.completeRequest = completeRequest; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("executeRequest") + public Optional getExecuteRequest() { + return executeRequest; + } + + @JsonProperty("cancelRequest") + public Optional getCancelRequest() { + return cancelRequest; + } + + @JsonProperty("completeRequest") + public Optional getCompleteRequest() { + return completeRequest; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AgentTaskRequest && equalTo((AgentTaskRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(AgentTaskRequest other) { + return executeRequest.equals(other.executeRequest) + && cancelRequest.equals(other.cancelRequest) + && completeRequest.equals(other.completeRequest); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.executeRequest, this.cancelRequest, this.completeRequest); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private Optional executeRequest = Optional.empty(); + + private Optional cancelRequest = Optional.empty(); + + private Optional completeRequest = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(AgentTaskRequest other) { + executeRequest(other.getExecuteRequest()); + cancelRequest(other.getCancelRequest()); + completeRequest(other.getCompleteRequest()); + return this; + } + + @JsonSetter(value = "executeRequest", nulls = Nulls.SKIP) + public Builder executeRequest(Optional executeRequest) { + this.executeRequest = executeRequest; + return this; + } + + public Builder executeRequest(ExecuteRequest executeRequest) { + this.executeRequest = Optional.ofNullable(executeRequest); + return this; + } + + @JsonSetter(value = "cancelRequest", nulls = Nulls.SKIP) + public Builder cancelRequest(Optional cancelRequest) { + this.cancelRequest = cancelRequest; + return this; + } + + public Builder cancelRequest(CancelRequest cancelRequest) { + this.cancelRequest = Optional.ofNullable(cancelRequest); + return this; + } + + @JsonSetter(value = "completeRequest", nulls = Nulls.SKIP) + public Builder completeRequest(Optional completeRequest) { + this.completeRequest = completeRequest; + return this; + } + + public Builder completeRequest(CompleteRequest completeRequest) { + this.completeRequest = Optional.ofNullable(completeRequest); + return this; + } + + public AgentTaskRequest build() { + return new AgentTaskRequest(executeRequest, cancelRequest, completeRequest, additionalProperties); + } + } +} diff --git a/src/main/java/com/anduril/types/BadRequestErrorBody.java b/src/main/java/com/anduril/types/BadRequestErrorBody.java new file mode 100644 index 00000000..2cd14ea1 --- /dev/null +++ b/src/main/java/com/anduril/types/BadRequestErrorBody.java @@ -0,0 +1,133 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.types; + +import com.anduril.core.ObjectMappers; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = BadRequestErrorBody.Builder.class) +public final class BadRequestErrorBody { + private final String error; + + private final Optional errorDescription; + + private final Map additionalProperties; + + private BadRequestErrorBody( + String error, Optional errorDescription, Map additionalProperties) { + this.error = error; + this.errorDescription = errorDescription; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("error") + public String getError() { + return error; + } + + @JsonProperty("error_description") + public Optional getErrorDescription() { + return errorDescription; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof BadRequestErrorBody && equalTo((BadRequestErrorBody) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(BadRequestErrorBody other) { + return error.equals(other.error) && errorDescription.equals(other.errorDescription); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.error, this.errorDescription); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static ErrorStage builder() { + return new Builder(); + } + + public interface ErrorStage { + _FinalStage error(@NotNull String error); + + Builder from(BadRequestErrorBody other); + } + + public interface _FinalStage { + BadRequestErrorBody build(); + + _FinalStage errorDescription(Optional errorDescription); + + _FinalStage errorDescription(String errorDescription); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements ErrorStage, _FinalStage { + private String error; + + private Optional errorDescription = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(BadRequestErrorBody other) { + error(other.getError()); + errorDescription(other.getErrorDescription()); + return this; + } + + @java.lang.Override + @JsonSetter("error") + public _FinalStage error(@NotNull String error) { + this.error = Objects.requireNonNull(error, "error must not be null"); + return this; + } + + @java.lang.Override + public _FinalStage errorDescription(String errorDescription) { + this.errorDescription = Optional.ofNullable(errorDescription); + return this; + } + + @java.lang.Override + @JsonSetter(value = "error_description", nulls = Nulls.SKIP) + public _FinalStage errorDescription(Optional errorDescription) { + this.errorDescription = errorDescription; + return this; + } + + @java.lang.Override + public BadRequestErrorBody build() { + return new BadRequestErrorBody(error, errorDescription, additionalProperties); + } + } +} diff --git a/src/main/java/com/anduril/types/UnauthorizedErrorBody.java b/src/main/java/com/anduril/types/UnauthorizedErrorBody.java new file mode 100644 index 00000000..bc0cbe4c --- /dev/null +++ b/src/main/java/com/anduril/types/UnauthorizedErrorBody.java @@ -0,0 +1,133 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.anduril.types; + +import com.anduril.core.ObjectMappers; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = UnauthorizedErrorBody.Builder.class) +public final class UnauthorizedErrorBody { + private final String error; + + private final Optional errorDescription; + + private final Map additionalProperties; + + private UnauthorizedErrorBody( + String error, Optional errorDescription, Map additionalProperties) { + this.error = error; + this.errorDescription = errorDescription; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("error") + public String getError() { + return error; + } + + @JsonProperty("error_description") + public Optional getErrorDescription() { + return errorDescription; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof UnauthorizedErrorBody && equalTo((UnauthorizedErrorBody) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(UnauthorizedErrorBody other) { + return error.equals(other.error) && errorDescription.equals(other.errorDescription); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.error, this.errorDescription); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static ErrorStage builder() { + return new Builder(); + } + + public interface ErrorStage { + _FinalStage error(@NotNull String error); + + Builder from(UnauthorizedErrorBody other); + } + + public interface _FinalStage { + UnauthorizedErrorBody build(); + + _FinalStage errorDescription(Optional errorDescription); + + _FinalStage errorDescription(String errorDescription); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements ErrorStage, _FinalStage { + private String error; + + private Optional errorDescription = Optional.empty(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(UnauthorizedErrorBody other) { + error(other.getError()); + errorDescription(other.getErrorDescription()); + return this; + } + + @java.lang.Override + @JsonSetter("error") + public _FinalStage error(@NotNull String error) { + this.error = Objects.requireNonNull(error, "error must not be null"); + return this; + } + + @java.lang.Override + public _FinalStage errorDescription(String errorDescription) { + this.errorDescription = Optional.ofNullable(errorDescription); + return this; + } + + @java.lang.Override + @JsonSetter(value = "error_description", nulls = Nulls.SKIP) + public _FinalStage errorDescription(Optional errorDescription) { + this.errorDescription = errorDescription; + return this; + } + + @java.lang.Override + public UnauthorizedErrorBody build() { + return new UnauthorizedErrorBody(error, errorDescription, additionalProperties); + } + } +} diff --git a/src/test/java/com/anduril/StreamTest.java b/src/test/java/com/anduril/StreamTest.java index 639827a1..a798b0f1 100644 --- a/src/test/java/com/anduril/StreamTest.java +++ b/src/test/java/com/anduril/StreamTest.java @@ -9,6 +9,9 @@ import com.anduril.core.Stream; import java.io.IOException; import java.io.StringReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -17,8 +20,9 @@ public final class StreamTest { @Test public void testJsonStream() { - List messages = List.of(Map.of("message", "hello"), Map.of("message", "world")); - List jsonStrings = messages.stream().map(StreamTest::mapToJson).collect(Collectors.toList()); + List> messages = + Arrays.asList(createMap("message", "hello"), createMap("message", "world")); + List jsonStrings = messages.stream().map(StreamTest::mapToJson).collect(Collectors.toList()); String input = String.join("\n", jsonStrings); StringReader jsonInput = new StringReader(input); Stream jsonStream = Stream.fromJson(Map.class, jsonInput); @@ -33,8 +37,8 @@ public void testJsonStream() { @Test public void testSseStream() { - List events = List.of(Map.of("event", "start"), Map.of("event", "end")); - List sseStrings = events.stream().map(StreamTest::mapToSse).collect(Collectors.toList()); + List> events = Arrays.asList(createMap("event", "start"), createMap("event", "end")); + List sseStrings = events.stream().map(StreamTest::mapToSse).collect(Collectors.toList()); String input = String.join("\n" + "\n", sseStrings); StringReader sseInput = new StringReader(input); Stream sseStream = Stream.fromSse(Map.class, sseInput); @@ -49,8 +53,9 @@ public void testSseStream() { @Test public void testSseStreamWithTerminator() { - List events = List.of(Map.of("message", "first"), Map.of("message", "second")); - List sseStrings = events.stream().map(StreamTest::mapToSse).collect(Collectors.toList()); + List> events = Arrays.asList(createMap("message", "first"), createMap("message", "second")); + List sseStrings = + new ArrayList<>(events.stream().map(StreamTest::mapToSse).collect(Collectors.toList())); sseStrings.add("data: [DONE]"); String input = String.join("\n" + "\n", sseStrings); StringReader sseInput = new StringReader(input); @@ -83,4 +88,10 @@ private static String mapToJson(Map map) { private static String mapToSse(Map map) { return "data: " + mapToJson(map); } + + private static Map createMap(String key, String value) { + Map map = new HashMap<>(); + map.put(key, value); + return map; + } }