Skip to content

Mock LLM Responder — Java source

Generate deterministic mock LLM API responses - chat completion JSON, SSE event streams with chunk timing, and a replay curl - for testing clients without an API key.

This is the Java implementation — the same logic the interactive tool runs, in a shareable, citable form.

// mock-llm-responder — Java port: deterministic mock LLM responses (seeded PRNG + token math).
import java.util.ArrayList;
import java.util.List;
import java.util.function.DoubleSupplier;

public class MockLlmResponder {
    static final String[] POEM_WORDS = {
        "cosmos", "nebula", "quantum", "signal", "photon", "drift", "orbit", "vector",
        "cipher", "lumen", "aurora", "echo", "helix", "nova", "pulse", "tide",
        "vertex", "zenith", "quasar", "ion", "halo", "flux", "prism", "comet",
    };
    /** FNV-1a 32-bit hash — turns the spec into a deterministic seed / id. */
    static int hashString(String s) {
        int h = 0x811c9dc5; // FNV offset basis
        for (int i = 0; i < s.length(); i++) { h ^= s.charAt(i); h *= 0x01000193; }
        return h;
    }
    /** mulberry32 — tiny seeded PRNG; same seed, same sequence, forever. */
    static DoubleSupplier mulberry32(int seed) {
        int[] a = { seed };
        return () -> {
            a[0] += 0x6d2b79f5;
            int x = a[0];
            int t = (x ^ (x >>> 15)) * (x | 1);
            t = (t + ((t ^ (t >>> 7)) * (t | 61))) ^ t;
            return Integer.toUnsignedLong(t ^ (t >>> 14)) / 4294967296.0;
        };
    }
    /** ~4 chars per token, floor of 1 — deterministic, no tokenizer needed. */
    static int tokenCount(String text) {
        return text.isEmpty() ? 0 : Math.max(1, (text.length() + 3) / 4);
    }
    /** Cut text so it fits in maxTokens tokens (4 chars each). */
    static String truncateToTokens(String text, int maxTokens) {
        if (tokenCount(text) <= maxTokens) return text;
        return text.substring(0, maxTokens * 4).stripTrailing();
    }
    /** One poem line of 5-7 vocabulary words. */
    static String makeLine(DoubleSupplier rng) {
        int n = 5 + (int) (rng.getAsDouble() * 3);
        StringBuilder b = new StringBuilder();
        for (int i = 0; i < n; i++)
            b.append(i > 0 ? " " : "").append(POEM_WORDS[(int) (rng.getAsDouble() * POEM_WORDS.length)]);
        return b.toString();
    }
    /** Poem-ish lorem, grown line by line until the token budget is full. */
    static String buildPoem(int seed, int maxTokens) {
        DoubleSupplier rng = mulberry32(seed);
        String text = "";
        for (;;) {
            String candidate = text.isEmpty() ? makeLine(rng) : text + "\n" + makeLine(rng);
            if (!text.isEmpty() && tokenCount(candidate) > maxTokens) break;
            text = candidate;
        }
        return truncateToTokens(text, maxTokens);
    }
    /** Split content into stream chunks. Chunks reassemble to the exact content. */
    static List<String> chunkContent(String content, int perChunk) {
        List<String> words = new ArrayList<>(), chunks = new ArrayList<>();
        for (int i = 0; i < content.length();) {
            int j = i; // scan one word token: non-space run + trailing whitespace
            while (j < content.length() && !Character.isWhitespace(content.charAt(j))) j++;
            while (j < content.length() && Character.isWhitespace(content.charAt(j))) j++;
            words.add(content.substring(i, j));
            i = j;
        }
        for (int k = 0; k < words.size(); k += perChunk) {
            StringBuilder b = new StringBuilder();
            for (int m = k; m < Math.min(k + perChunk, words.size()); m++) b.append(words.get(m));
            chunks.add(b.toString()); // chunks rejoin to the exact original content
        }
        return chunks;
    }
    public static void main(String[] args) {
        String spec = "streamed-lorem|mock-gpt-4o-mini|24", poem = buildPoem(hashString(spec + "|poem"), 24);
        System.out.printf("id=chatcmpl-mock-%08x%n", hashString(spec + "|id"));
        System.out.println(poem);
        System.out.println("tokens=" + tokenCount(poem) + " chunks=" + chunkContent(poem, 4).size());
    }
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →