Skip to main content
Version: 1.13.0-dev

Use DVARA from Java

Point an OpenAI-compatible Java client at DVARA when your service needs policy, PII controls, audit evidence, and cost attribution around model calls. The client API stays familiar; DVARA governs each request before it reaches a configured provider.

Send your first governed request​

You need a running DVARA deployment, a registered provider that serves the model in your request, and a workspace API key. Follow the Quickstart if you do not have them yet.

Set the connection outside source control:

export OPENAI_BASE_URL="http://localhost:8080/v1"
export OPENAI_API_KEY="<your-dvara-api-key>"

Use a key with completions:write. A key with no scopes is unrestricted, but a key with any scopes can call only the endpoint families named by those scopes. See Authenticate data-plane calls for the complete map.

Add the official OpenAI Java client:

<dependency>
<groupId>com.openai</groupId>
<artifactId>openai-java</artifactId>
<version>4.68.0</version>
</dependency>

The client reads OPENAI_BASE_URL and OPENAI_API_KEY. A raw response keeps DVARA's trace header alongside the parsed Chat Completions body:

import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.http.HttpResponseFor;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;

OpenAIClient client = OpenAIOkHttpClient.fromEnv();

ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model("gpt-4o")
.addSystemMessage("Answer in one sentence.")
.addUserMessage("Why should an API key be rotated?")
.maxTokens(80L)
.build();

HttpResponseFor<ChatCompletion> raw = client.chat().completions()
.withRawResponse()
.create(params);
ChatCompletion completion = raw.parse();

System.out.println(completion.choices().get(0).message().content().orElse(""));
System.out.println("DVARA trace: "
+ raw.headers().values("x-trace-id").stream().findFirst().orElse("missing"));

Example output:

Regular rotation limits the time a leaked API key can be used.
DVARA trace: 043793a6ac754c9c9d1bc5d4f525f827

The wording and token counts vary by model. When audit storage is configured, search for the trace ID in Flightdeck or your audit output. The completed call has a GATEWAY_RESPONSE event with its model, provider, outcome, and available usage data.

The model must be served by a provider registered in your DVARA deployment. Use GET /v1/models to inspect the current provider result, then use the exact identifier your deployment exposes.

Stream a Chat Completions response​

import com.openai.core.http.StreamResponse;
import com.openai.models.chat.completions.ChatCompletionChunk;

ChatCompletionCreateParams streamParams = ChatCompletionCreateParams.builder()
.model("gpt-4o")
.addUserMessage("Write a two-line release note about key rotation.")
.maxTokens(80L)
.build();

try (StreamResponse<ChatCompletionChunk> stream =
client.chat().completions().createStreaming(streamParams)) {
stream.stream()
.flatMap(chunk -> chunk.choices().stream())
.flatMap(choice -> choice.delta().content().stream())
.forEach(System.out::print);
}
System.out.println();

Streaming response enforcement follows the workspace's configured streaming posture. It is not the same as buffering and scanning a complete non-streaming response. See Streaming before using a stream for regulated content.

Use the Responses API​

DVARA supports text and image input, instructions, metadata, structured output through text.format, your own function tools with tool_choice (from 1.9.0), and synchronous or streaming Responses API calls. The same completions:write scope covers this endpoint.

import com.openai.models.responses.Response;
import com.openai.models.responses.ResponseCreateParams;

ResponseCreateParams responseParams = ResponseCreateParams.builder()
.model("gpt-4o")
.instructions("Answer in one sentence.")
.input("Name one practical reason to keep an AI audit trail.")
.build();

Response response = client.responses().create(responseParams);
response.output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));

The endpoint is stateless. It refuses store: true, previous_response_id, reusable prompt objects, background mode, built-in tools such as web search, any include other than reasoning.encrypted_content, and a service_tier other than auto or default, with HTTP 400 and unsupported_capability. When the model returns a function call, your application or agent framework still executes the function.

Call Anthropic, Bedrock, or Gemini models​

DVARA exposes an OpenAI-compatible client surface. Keep using the OpenAI Java client and change the model identifier to one served by your configured Anthropic, Amazon Bedrock, or Google provider:

for (String model : List.of(
"<anthropic-model>", "<bedrock-model>", "<gemini-model>")) {
ChatCompletion result = client.chat().completions().create(
ChatCompletionCreateParams.builder()
.model(model)
.addUserMessage("Reply with the provider name.")
.maxTokens(30L)
.build());
System.out.println(model + ": "
+ result.choices().get(0).message().content().orElse(""));
}

Replace each placeholder with an identifier returned by your deployment. The Bedrock Converse request shape is not a DVARA endpoint. DVARA does serve two other native shapes: the Anthropic Messages API at /v1/messages (from 1.8.5; see Govern Claude Code) and Gemini's generateContent API at /v1/gemini (from 1.9.0; see Govern Gemini CLI). Point the SDK's base URL at the Gateway (with no /v1) for Anthropic, or at <gateway>/v1/gemini for Gemini, and use a DVARA workspace key.

Connect LangChain4j​

Use LangChain4j's OpenAI-compatible model and the full DVARA /v1 base URL:

<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.20.0</version>
</dependency>
import dev.langchain4j.model.openai.OpenAiChatModel;

OpenAiChatModel model = OpenAiChatModel.builder()
.baseUrl(System.getenv("OPENAI_BASE_URL"))
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o")
.build();

String answer = model.chat("Give one reason to retain model-call evidence.");
System.out.println(answer);

LangChain4j agents use Chat Completions function calling through this model. The agent process executes each selected tool, so enforce tool authorization there as well as any configured DVARA governance.

Connect Spring AI​

Use Spring AI's current OpenAI model starter. Manage its version through the Spring AI BOM used by your application:

<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>

Spring AI appends /v1/chat/completions to base-url. Set the DVARA origin, not the /v1 client base used by the official OpenAI SDK:

spring:
ai:
openai:
base-url: http://localhost:8080
api-key: ${DVARA_API_KEY}
chat:
options:
model: gpt-4o
temperature: 0

Call it through ChatClient:

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

@Service
public class GovernedChatService {
private final ChatClient chatClient;

public GovernedChatService(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

public String answer(String question) {
return chatClient.prompt().user(question).call().content();
}

public Flux<String> stream(String question) {
return chatClient.prompt().user(question).stream().content();
}
}

Spring AI retries independently of DVARA. Its OpenAI client currently defaults to three retries. Set spring.ai.openai.max-retries deliberately so one application action does not create more provider attempts than your reliability and cost policy allows.

Create embeddings​

An embeddings call needs embeddings:write when the key has a nonempty scope list. The embedding model must be available through a configured provider. Use the official SDK's client.embeddings() service or the corresponding framework model with the same DVARA base URL and key.

DVARA applies configured request-side controls and records available usage, but it does not run model-text response scans over numeric vectors. The vector dimension is controlled by the selected model.

Handle a refusal​

DVARA uses one error envelope for authentication, policy, budget, provider, and validation failures. The official Java client raises OpenAIServiceException for a non-success response:

import com.openai.errors.OpenAIServiceException;

try {
ChatCompletion result = client.chat().completions().create(params);
System.out.println(result.choices().get(0).message().content().orElse(""));
} catch (OpenAIServiceException exception) {
System.err.println("DVARA refused the request: HTTP " + exception.statusCode());
System.err.println(exception.body());
}

Parse the returned DVARA error envelope in your service's normal HTTP error layer and retain its trace_id. For example, a valid key scoped only to models:read receives HTTP 403, type: "permission_error", and code: "api_key_scope". See Error handling for the complete contract.

Continue the integration​