Mock LLM Responder — C# 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 C# implementation — the same logic the interactive tool runs, in a shareable, citable form.
// mock-llm-responder — C# port: deterministic mock LLM responses (seeded PRNG + token math).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
static class MockLlmResponder
{
static readonly string[] PoemWords = {
"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 uint HashString(string s)
{
uint h = 0x811c9dc5;
foreach (char c in s) { h ^= c; h *= 0x01000193; }
return h;
}
// mulberry32 — tiny seeded PRNG; same seed, same sequence, forever.
static Func<double> Mulberry32(uint seed)
{
return () => {
seed += 0x6d2b79f5;
uint t = (seed ^ (seed >> 15)) * (seed | 1);
t = (t + ((t ^ (t >> 7)) * (t | 61))) ^ t;
return (t ^ (t >> 14)) / 4294967296.0;
};
}
// ~4 chars per token, floor of 1 — deterministic, no tokenizer needed.
static int TokenCount(string text) =>
text.Length == 0 ? 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[..(maxTokens * 4)].TrimEnd();
}
// One poem line of 5-7 vocabulary words.
static string MakeLine(Func<double> rng)
{
int n = 5 + (int)(rng() * 3);
var words = new string[n];
for (int i = 0; i < n; i++) words[i] = PoemWords[(int)(rng() * PoemWords.Length)];
return string.Join(" ", words);
}
// Poem-ish lorem, grown line by line until the token budget is full.
static string BuildPoem(uint seed, int maxTokens)
{
var rng = Mulberry32(seed);
string text = "";
for (;;)
{
string candidate = text.Length == 0 ? MakeLine(rng) : text + "\n" + MakeLine(rng);
if (text.Length != 0 && 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)
{
var words = Regex.Matches(content, @"\S+\s*");
var chunks = new List<string>();
for (int i = 0; i < words.Count; i += perChunk)
chunks.Add(string.Concat(Enumerable.Range(i, Math.Min(perChunk, words.Count - i))
.Select(j => words[j].Value)));
return chunks;
}
static void Main()
{
const string spec = "streamed-lorem|mock-gpt-4o-mini|24";
string poem = BuildPoem(HashString(spec + "|poem"), 24);
Console.WriteLine($"id=chatcmpl-mock-{HashString(spec + "|id"):x8}");
Console.WriteLine(poem);
Console.WriteLine($"tokens={TokenCount(poem)} chunks={ChunkContent(poem, 4).Count}");
}
}
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 →