Docs/Integrations/Java Sdk

Java SDK

The Java SDK has two parts:

  • Tracing (com.ants.platform.tracing and com.ants.platform.otel). Built on OpenTelemetry. It exports spans to https://<your-ants-host>/api/public/otel/v1/traces and maps them to traces and observations.
  • API client (com.ants.platform.client.AntsPlatformClient). A typed client for the public REST API: traces, observations, sessions, scores, prompts, datasets and more.
Value
Maven coordinatesai.agenticants:ants-platform-java
Current version0.3.0
Java version17 or later
AuthProject public key (pk-ap-...) and secret key (sk-ap-...)

Create a key pair under Project Settings > API Keys. See API Keys.

Install

xml
<dependency> <groupId>ai.agenticants</groupId> <artifactId>ants-platform-java</artifactId> <version>0.3.0</version> </dependency>

The SDK brings in the OpenTelemetry API, SDK and OTLP exporter, Jackson and OkHttp.

Configure

The tracing setup reads these environment variables. Values set on the builder take precedence.

VariablePurpose
ANTS_PLATFORM_PUBLIC_KEYProject public key
ANTS_PLATFORM_SECRET_KEYProject secret key
ANTS_PLATFORM_BASE_URLYour ANTS Platform URL, for example https://<your-ants-host>
ANTS_PLATFORM_TRACING_ENVIRONMENTEnvironment label on every span, for example production
ANTS_PLATFORM_RELEASERelease label on every span
⚠

The Java SDK reads ANTS_PLATFORM_BASE_URL, not ANTS_PLATFORM_HOST (the Python SDK variable). If neither the variable nor .baseUrl(...) is set, the SDK sends to https://api.agenticants.ai. Set it explicitly for any other deployment.

Trace an agent

Configure tracing once at startup

java
AntsPlatformOtel.configure(AntsPlatformOtel.options() .publicKey(System.getenv("ANTS_PLATFORM_PUBLIC_KEY")) .secretKey(System.getenv("ANTS_PLATFORM_SECRET_KEY")) .baseUrl(System.getenv("ANTS_PLATFORM_BASE_URL")) .environment("production") .agent("support-agent", "Support Agent"));

configure registers a global OpenTelemetry instance with the ANTS Platform span processor. .agent(name, displayName) tags every span with a stable agent ID so the agent appears in the AI Agent Center. Keep the agent name stable. The display name can change later.

Create observations

java
String answer = Ants.observe("support-agent", ObservationType.AGENT, agent -> { agent.input(Map.of("question", question)); agent.updateTrace(TraceAttributes.builder() .name("support-request") .userId("user-123") .sessionId("session-abc") .tags(List.of("support")) .build()); AntsObservation search = Ants.startObservation("kb-search", ObservationType.RETRIEVER); search.input(Map.of("query", question)).output(Map.of("documents", 3)).end(); AntsGeneration gen = Ants.startGeneration("draft-answer") .model("gpt-4o-mini") .modelParameters(Map.of("temperature", 0.2)) .input(List.of(Map.of("role", "user", "content", question))); String text = callModel(question); gen.output(Map.of("role", "assistant", "content", text)) .usage(120, 80) .end(); agent.output(text); return text; });

Observations started inside observe nest under it automatically. The span ends when the function returns. If it throws, the error is recorded on the observation (level ERROR) and rethrown.

Flush before the process exits

java
AntsPlatformOtel.shutdown();

Use AntsPlatformOtel.flush() to send buffered spans without shutting down, for example at the end of a request in a long-running service.

Cost is calculated by ANTS Platform from the model name and token usage. Pass .cost(Map.of(...)) on a generation to send your own cost instead.

Tracing API

Entry points (Ants)

MethodWhat it does
startObservation(name) / startObservation(name, type)Starts an observation under the current active span. Call .end() yourself.
startObservation(name, type, parent)Starts an observation under an explicit parent.
startGeneration(name) / startGeneration(name, parent)Starts a generation. Call .end() yourself.
observe(name, type, fn)Runs fn with a new active observation and returns its result. Ends the span, records errors.
observeGeneration(name, fn)Same as observe for a generation.
startActiveObservation(name, type, consumer) / startActiveGeneration(name, consumer)Same as observe without a return value.
updateActiveTrace(attrs)Sets trace attributes on the current active span.
currentObservation()Returns the current active observation, or null.

Observation types (ObservationType)

SPAN, GENERATION, AGENT, TOOL, RETRIEVER, CHAIN, EMBEDDING, EVALUATOR, GUARDRAIL, EVENT. GENERATION and EMBEDDING accept model, usage and cost fields.

Observation methods

MethodApplies to
input(obj), output(obj), metadata(obj)All
level(text) with DEBUG, DEFAULT, WARNING or ERROR; statusMessage(text); version(text)All
recordError(throwable)All
updateTrace(TraceAttributes)All
startChild(name, type), startChildGeneration(name)All
end(), end(Instant)All
traceId(), id()All
model(name), modelParameters(map)Generations and embeddings
usage(input, output), usage(input, output, total), usage(map)Generations and embeddings
cost(map), completionStartTime(instant), prompt(name, version)Generations and embeddings

Trace attributes (TraceAttributes.builder())

name, userId, sessionId, version, release, input, output, metadata, tags, isPublic, environment.

Span processor options (AntsPlatformOtel.options())

publicKey, secretKey, baseUrl, environment, release, agent(name) or agent(name, displayName), flushIntervalMillis, timeoutMillis.

Use your own OpenTelemetry setup

AntsPlatformSpanProcessor is a standard OpenTelemetry SpanProcessor. If your application already builds its own SdkTracerProvider, add the processor to it instead of calling AntsPlatformOtel.configure:

java
SdkTracerProvider provider = SdkTracerProvider.builder() .addSpanProcessor(AntsPlatformSpanProcessor.builder() .agent("support-agent") .build()) .build();

Spans from other OpenTelemetry instrumentation registered on the same provider are exported too. You can also export from any OpenTelemetry SDK without this library: send OTLP/HTTP to https://<your-ants-host>/api/public/otel with an Authorization: Basic <base64(pk:sk)> header. See Sending Data In.

REST API client

java
AntsPlatformClient client = AntsPlatformClient.builder() .url(System.getenv("ANTS_PLATFORM_BASE_URL")) .credentials( System.getenv("ANTS_PLATFORM_PUBLIC_KEY"), System.getenv("ANTS_PLATFORM_SECRET_KEY")) .build(); try { var traces = client.trace().list(); var trace = client.trace().get(traceId); } catch (AntsPlatformClientApiException e) { System.err.println(e.statusCode() + " " + e.body()); }

The client exposes one accessor per API resource: trace(), observations(), sessions(), score(), scoreV2(), scoreConfigs(), prompts(), promptVersion(), datasets(), datasetItems(), datasetRunItems(), comments(), annotationQueues(), metrics(), models(), media(), ingestion(), projects(), organizations(), scim() and health(). Builder options: url, credentials, timeout (seconds) and httpClient (a custom OkHttp client).

Use the tracing API above to send traces. The low-level ingestion() endpoint is available for custom pipelines.

Guardrails

The SDK includes com.ants.platform.guardrails.AntsGuardrailsClient and provider wrappers that check prompts and responses against an agent's guardrail policy. See AI Guardrails.

Each check accepts up to 1,000,000 characters of text; longer text is checked in overlapping windows (see Long text). The Java SDK does not ask for the WARNING result, so a check that warns returns PASS. The warning is still recorded in AI Violations.

Tool governance

From 0.3.0, com.ants.platform.guardrails.tools.AntsToolGuard checks an agent's tool calls against its tool permissions before the tool runs. It is on by default when agentId is set, and changes nothing until the agent has an approved tool.

java
AntsToolGuard tools = AntsToolGuard.builder() .antsApiKey(publicKey + ":" + secretKey) .baseUrl(System.getenv("ANTS_PLATFORM_BASE_URL")) .agentId("<agent-id>") .agentName("support-agent") .build(); try { Refund refund = tools.runAs(idToken, () -> tools.guardTool("issue_refund", Map.of("order_id", "A-1001", "amount", 750), () -> payments.refund("A-1001", 750))); } catch (ToolApprovalDeniedException e) { // a person denied the call, or nobody approved it in time } catch (ToolNotAllowedException e) { // blocked by the agent's tool permissions }
  • guardTool(name, arguments, supplier) runs the supplier only when the call is allowed and, when needed, approved.
  • When the agent's AI Guardrails policy is Block or Redact, a call that breaks a rule throws ToolNotAllowedException. Under Audit Only, or with no policy, the call runs and the violation is reported in the background.
  • A call that needs approval creates an approval request and waits for the decision. A denial, an expiry or no answer within approvalTimeout throws ToolApprovalDeniedException.
  • Tool calls of a suspended agent throw ToolNotAllowedException, even when the agent has no policy.
MethodUse
guardTool(...), enforceTool(name, arguments), enforceTools(...)Check calls and throw when they are blocked or not approved
checkTool(name), checkTools(...)Check calls and return a ToolCheckResult; never throw
runAs(idToken, supplier) / setUserToken(idToken)Verify the OIDC ID token of the user the agent acts for, for group-limited tools. The user is kept per thread.
checkDefinitions(...) / enforceDefinitions(...)Compare MCP tool definitions with the pinned ones
requestApproval(...), approvalStatus(...), awaitApproval(...)Handle approvals yourself
Builder optionDefaultDescription
enforceTools(boolean)truePass false to turn tool governance off
failMode(FailMode)OPENCLOSED blocks tool calls when the tool settings were never loaded
approvalTimeout(Duration)5 minutesHow long to wait for an approval
approvalPollInterval(Duration)2 secondsHow often to ask for the decision

The tool settings are refreshed about every minute, and the last copy is kept if a refresh fails. Rate limits are counted in the process. Deny patterns use RE2 syntax, as on the platform.

Troubleshooting

  • 401 on export. Check the key pair and that both keys belong to the project you expect. The SDK logs a warning at startup when a key is missing.
  • No traces from a short-lived process. Call AntsPlatformOtel.shutdown() before exit so buffered spans are sent.
  • Traces go to the wrong host. Set ANTS_PLATFORM_BASE_URL or .baseUrl(...). The SDK does not read ANTS_PLATFORM_HOST.
  • Agent missing from the AI Agent Center. Set .agent(...) on the span processor options.
© 2026 ANTS Platform, Inc.Docs v1.0 · Last updated June 2026