Skip to content

About

A Java 21 and Spring Boot starter for OpenCode Zen, with request builders, model policies, and SSE utilities.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

OpenCode Zen for Java

A Spring Boot starter for OpenCode Zen.

Build Java 21 Spring Boot 3.3.2 JitPack MIT License

English · 简体中文

Features · Quick start · Usage · License

Build OpenCode Zen requests in Java with consistent headers, credentials, session identifiers, and tool declarations. The starter provides an auto-configured request factory; your application sends requests with its own HTTP client and handles the responses.

Features

  • Three inference formats — request construction for Chat Completions, Responses, and Anthropic Messages.
  • Spring Boot integration — inject OpenCodeZenRequestFactory, or provide your own bean to override the default.
  • Request compatibility — a bundled OpenCode 2.1.4 client identity, the official 2.x system prompt and the complete official tool set (the application's tools leave under clint_ names), a fresh session identifier per request (sticky per-conversation sessions behind opencode.zen.session-affinity), and a per-request project identifier.
  • Model and credential policies — catalog parsing, free-model admission rules, and public versus API-key authentication.
  • Streaming utilities — SSE frame decoding, JSON event reading, and upstream error classification.
  • Explicit transport choices — helpers for direct, JVM-configured, or HTTP proxy connections. No automatic route switching; retrying is opt-out through OpenCodeZenRetryPolicy (a rate-limited 429 asks again under a fresh ledger; nothing else is retried).

This project supplies request and protocol utilities. Credential storage, routing, budgets, tool execution, and application workflows belong to the consuming application.

Quick start

Requirements

  • Java 21 or later.
  • Spring Boot dependencies are built against 3.3.2; other versions should be verified in your application.
  • Artifacts are distributed through JitPack. The documented version is v1.5.5, including the leading v.

Install

Gradle Kotlin DSL

repositories {
    mavenCentral()
    maven { url = uri("https://jitpack.io") }
}

dependencies {
    implementation("com.github.BangShou1st.opencode-zen:opencode-zen-spring-boot-starter:v1.5.5")
}

If your build centralizes repositories, add JitPack to dependencyResolutionManagement.repositories in settings.gradle.kts.

Maven

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>com.github.BangShou1st.opencode-zen</groupId>
        <artifactId>opencode-zen-spring-boot-starter</artifactId>
        <version>v1.5.5</version>
    </dependency>
</dependencies>

Public artifact downloads require no token. JitPack may need time to build a tag on its first resolution; check the build page if a dependency is unavailable.

Build and send a request

The starter registers the request factory automatically. No library configuration is required.

import com.sharedlibs.opencodezen.autoconfigure.OpenCodeZenHttpClients;
import com.sharedlibs.opencodezen.autoconfigure.OpenCodeZenRequestFactory;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.HttpResponse;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service
public class ZenChatService {
    private final OpenCodeZenRequestFactory factory;
    private final HttpClient http = OpenCodeZenHttpClients.system();

    public ZenChatService(OpenCodeZenRequestFactory factory) {
        this.factory = factory;
    }

    public HttpResponse<String> chat(UUID conversationId, String model, String prompt)
            throws IOException, InterruptedException {
        var payload = Map.<String, Object>of(
                "model", model,
                "messages", List.of(Map.of("role", "user", "content", prompt)));
        // true/null selects public credentials for an eligible free model.
        // For a paid model, pass false and your API key instead.
        var request = factory.newConversationChatRequest(
                true, null, conversationId, payload);
        return http.send(request, HttpResponse.BodyHandlers.ofString());
    }
}

Pass an eligible free-model ID from the current catalog and admission policy. Reuse the same conversationId across turns. The example returns the upstream status and raw body; the application must check the status and handle JSON or SSE before exposing a result.

Usage

Choose an inference format

Format Protocol Inference path
Chat Completions ZenModelProtocol.CHAT /inference/openai/v1/chat/completions
Responses ZenModelProtocol.RESPONSES /inference/openai/v1/responses
Anthropic Messages ZenModelProtocol.ANTHROPIC /inference/anthropic/v1/messages?beta=true

The 2.1 client groups its inference routes by provider family; OpenCodeZenProtocolPolicy.inferenceEndpoint(protocol) returns the grouped URL for the bundled base https://opencode.ai/inference/v1, and a custom base URL keeps the flat route. Use newConversationInferenceRequest(endpoint, protocol, freeModel, apiKey, conversationId, payload) for an explicit endpoint and format, or newEphemeralInferenceRequest(endpoint, protocol, freeModel, apiKey, payload) for a one-off call. The endpoint path must match the protocol.

Read SSE events

For a streaming payload, request "stream": true and use an input-stream body handler:

import com.sharedlibs.opencodezen.OpenCodeZenSseEventReader;

// http and request are supplied by the application.
var response = http.send(request, HttpResponse.BodyHandlers.ofInputStream());
try (var body = response.body()) {
    if (response.statusCode() != 200) {
        throw new IOException("OpenCode Zen returned HTTP " + response.statusCode());
    }
    OpenCodeZenSseEventReader.read(body, event -> {
        // Handle event.name(), event.payload(), and event.done().
    });
}

The reader handles SSE framing and JSON events. Your adapter must assemble protocol-specific output and filter tool calls. Tool calls in a reply name the clint_ wire spelling; restore the names your application declared through the renames that OpenCodeZenProtocolPolicy.shapeEnvelope returns. The appended official tools are declarations only and must never be executed. Only tools explicitly authorized by the caller may run.

Credentials, networking, and errors

  • Free-model requests use the public credential; paid models require an API key. The caller supplies the free/paid decision using the model policies.
  • OpenCodeZenHttpClients.system() uses the JVM proxy selector. It does not guarantee support for HTTP_PROXY / HTTPS_PROXY environment variables.
  • Use direct() for a direct connection or explicitHttpProxy(host, port) for an explicit HTTP proxy.
  • OpenCodeZenUpstreamDiagnostics.classify(statusCode, bodyBytes) distinguishes abuse rejection, free-tier rejection, rate limiting, and other failures. A 429 whose body carries the IP-abuse wording is a block, not a rate limit, and is never retried.
  • OpenCodeZenRetryPolicy carries the retry decision and its knobs (aligned with upstream OpenCode-Zen-FreeX v0.5.10/v0.5.11): the tier ledgers its free quota per project id and egress together, so a rate-limited 429 is worth asking again under a fresh ledger, and so is a request that never got an answer (looksLikeTransportFailure). The count defaults to 2 (OPENCODE_ZEN_FREE_RETRY_429=0 turns it off, 5 is the ceiling) and the first wait is 1200 ms, doubled per attempt, capped at 5 s (OPENCODE_ZEN_FREE_RETRY_WAIT_MS overrides). The loop belongs to the caller: rebuild the request through the same factory method — every call mints fresh session, request and project identifiers, which is the fresh ledger — and hand the failure of the last attempt on unchanged when the retries are spent.
  • opencode.zen.user-agent, opencode.zen.session-affinity (default false) and opencode.zen.relay-url (default blank) are the library's configuration properties. With affinity off, every request leaves as its own session; with affinity on, one conversation key keeps one sticky session for the factory's lifetime. The default auto needs no configuration: an already-running local Bun relay wins, then the library starts the bundled relay script itself — with the local Bun, or, when none is installed, with a Bun runtime it downloads once (pinned release, SHA-256 verified, cached per user). From the second run on, everything is offline. Only an offline machine without Bun goes direct, which the tier refuses with 429 FreeUsageLimitError; relay-url also accepts an explicit relay address or none. Credentials remain application-owned.

Integration notes

  • With session-affinity enabled, conversation sessions are cached in memory within the factory instance; the mapping does not persist across restarts.
  • Inference overloads accepting incomingHeaders selectively forward project, validated session, and Anthropic beta/version headers. They do not allow incoming headers to override credentials.
  • Legacy newConversationRequest / newEphemeralRequest methods return header-bearing builders only. For inference, apply OpenCodeZenProtocolPolicy.applyRequiredEnvelope yourself or use the complete inference methods above.

Project structure

Module Purpose
opencode-zen-spring-boot-starter Dependency entry point for Spring Boot applications.
opencode-zen-spring-boot-autoconfigure Protocol policies, model parsing, SSE utilities, properties, and request factory.

Acknowledgments

The bundled client profile, official prompt and official tool set reference OpenCode-Zen-FreeX v0.5.9. Source attribution and its MIT notice are retained in THIRD_PARTY_NOTICES.md.

This is an independent Java integration, unaffiliated with the OpenCode project. Model availability, pricing, and access are controlled by the upstream service; using this package does not grant service access.

License

MIT © 2026 BangShou1st. Third-party components retain their respective licenses.

About

A Java 21 and Spring Boot starter for OpenCode Zen, with request builders, model policies, and SSE utilities.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages