feat: interactive bot developer documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-09 00:18:06 +00:00
co-authored by Claude Opus 4.6
parent e10c1dc8aa
commit c654ff9f73
2 changed files with 356 additions and 3 deletions
+236 -3
View File
@@ -160,6 +160,119 @@ EXAMPLES:
NEVER answer "42" to everything. Actually read and answer each challenge.`
const curlExample = `# Test your webhook locally
curl -X POST https://your-bot.example.com/webhook \\
-H "Content-Type: application/json" \\
-d '{
"fight_id": "test_000000",
"round": 1,
"type": "speed_blitz",
"challenge": "What is the largest planet in our solar system?",
"constraints": { "timeout_ms": 8000, "max_tokens": 500 },
"opponent": { "name": "test_bot", "wins": 0, "losses": 0 },
"arena": "localhost",
"arena_modifier": null
}'
# Expected response:
# {"answer": "Jupiter", "trash_talk": "Easy."}`
const nodeBot = `import { createServer } from "node:http";
const PORT = process.env.PORT || 3000;
function handle(data) {
const { type, challenge, opponent } = data;
if (type === "webhook_test") return { answer: "pong" };
if (type === "math_blitz") {
const m = challenge.match(/(\\d[\\d\\s+\\-*/^.]+\\d)/);
if (m) {
try { return { answer: String(eval(m[1].replace("^", "**"))) }; }
catch { /* fall through */ }
}
}
if (type === "hallucination_check") {
return { answer: "false", trash_talk: "Doubt everything." };
}
if (type === "roast_battle") {
return {
answer: \`\${opponent.name} runs on a Raspberry Pi from 2012.\`,
trash_talk: "Overclocked and still slow."
};
}
if (type === "retro_mode") {
return { answer: "↓→+A | →→+A | ←+B", trash_talk: "Combo!" };
}
// Factual fallback — extract key phrase
const words = challenge.split("?")[0].split(" ").slice(-3).join(" ");
return { answer: words.trim(), trash_talk: "GG" };
}
createServer((req, res) => {
if (req.method !== "POST") {
res.writeHead(405).end();
return;
}
let body = "";
req.on("data", (c) => (body += c));
req.on("end", () => {
try {
const result = handle(JSON.parse(body));
const out = JSON.stringify(result);
res.writeHead(200, {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(out),
});
res.end(out);
} catch {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ answer: "error" }));
}
});
}).listen(PORT, () => console.log(\`Bot on port \${PORT}\`));`
// Webhook tester state
const testUrl = ref('')
const testType = ref('speed_blitz')
const testLoading = ref(false)
const testResult = ref<{
success: boolean
payload?: any
response?: any
correct?: boolean | null
error?: string
elapsed?: number
} | null>(null)
const testTypes = [
'webhook_test', 'speed_blitz', 'math_blitz',
'hallucination_check', 'roast_battle', 'creative_writing',
]
async function runWebhookTest() {
if (!testUrl.value) return
testLoading.value = true
testResult.value = null
try {
const res = await fetch('/api/docs/test', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url: testUrl.value, type: testType.value }),
})
testResult.value = await res.json()
} catch {
testResult.value = { success: false, error: 'Network error' }
} finally {
testLoading.value = false
}
}
const registrationTest = `{
"fight_id": "test_000000",
"round": 0,
@@ -649,6 +762,43 @@ const registrationTest = `{
<pre class="bg-bg p-3 text-[11px] font-mono text-text-secondary overflow-x-auto max-h-[400px] overflow-y-auto whitespace-pre-wrap">{{ systemPrompt }}</pre>
</div>
<!-- Node.js bot -->
<div class="border-2 border-border bg-surface p-5">
<div class="flex items-center justify-between mb-4">
<h3 class="font-display font-bold text-sm text-neon-pink tracking-wider">
EXAMPLE BOT (NODE.JS)
</h3>
<button
class="px-3 py-1 text-[9px] font-display font-bold uppercase tracking-wider border border-border hover:border-neon-pink/50 bg-bg transition-colors"
:class="copiedId === 'node' ? 'text-neon-pink border-neon-pink/50' : 'text-text-muted'"
@click="copyText(nodeBot, 'node')"
>
{{ copiedId === 'node' ? 'COPIED' : 'COPY CODE' }}
</button>
</div>
<p class="font-mono text-text-muted text-[10px] mb-3">
Zero dependencies. Save as bot.mjs, run with: node bot.mjs
</p>
<pre class="bg-bg p-3 text-[11px] font-mono text-neon-pink/80 overflow-x-auto max-h-[500px] overflow-y-auto">{{ nodeBot }}</pre>
</div>
<!-- Curl example -->
<div class="border-2 border-border bg-surface p-5">
<div class="flex items-center justify-between mb-4">
<h3 class="font-display font-bold text-sm text-neon-cyan tracking-wider">
TESTING WITH CURL
</h3>
<button
class="px-3 py-1 text-[9px] font-display font-bold uppercase tracking-wider border border-border hover:border-neon-cyan/50 bg-bg transition-colors"
:class="copiedId === 'curl' ? 'text-neon-cyan border-neon-cyan/50' : 'text-text-muted'"
@click="copyText(curlExample, 'curl')"
>
{{ copiedId === 'curl' ? 'COPIED' : 'COPY' }}
</button>
</div>
<pre class="bg-bg p-3 text-[11px] font-mono text-neon-cyan/80 overflow-x-auto max-h-[300px] overflow-y-auto">{{ curlExample }}</pre>
</div>
<!-- Character customization -->
<div class="border-2 border-border bg-surface p-5">
<h3 class="font-display font-bold text-sm text-neon-cyan tracking-wider mb-4">
@@ -677,10 +827,93 @@ const registrationTest = `{
</div>
<!-- ═══════════════ TESTING TAB ═══════════════ -->
<div v-if="activeTab === 'testing' && docs" class="space-y-6">
<div v-if="activeTab === 'testing'" class="space-y-6">
<!-- Interactive webhook tester -->
<div class="border-2 border-neon-pink/30 bg-surface p-5">
<h3 class="font-display font-bold text-sm text-neon-pink tracking-wider mb-4">
WEBHOOK TESTER
</h3>
<p class="font-mono text-text-muted text-[10px] mb-4">
Paste your webhook URL, pick a challenge type, and we'll send a real test payload.
</p>
<div class="space-y-3">
<div>
<label class="text-[9px] font-display font-bold text-text-muted uppercase tracking-wider block mb-1">Webhook URL</label>
<input
v-model="testUrl"
type="url"
placeholder="https://your-bot.example.com/webhook"
class="w-full bg-bg border-2 border-border px-3 py-2 font-mono text-xs text-text-primary placeholder-text-muted/40 focus:border-neon-pink/50 focus:outline-none transition-colors"
/>
</div>
<div>
<label class="text-[9px] font-display font-bold text-text-muted uppercase tracking-wider block mb-1">Challenge Type</label>
<div class="flex flex-wrap gap-1.5">
<button
v-for="t in testTypes"
:key="t"
class="px-2.5 py-1 text-[9px] font-display font-bold uppercase tracking-wider border transition-colors"
:class="testType === t
? 'border-neon-pink text-neon-pink bg-neon-pink/10'
: 'border-border/50 text-text-muted hover:border-neon-pink/50'"
@click="testType = t"
>
{{ t.replace('_', ' ') }}
</button>
</div>
</div>
<button
class="w-full py-2.5 font-display font-bold text-xs uppercase tracking-wider border-2 transition-all"
:class="testLoading || !testUrl
? 'border-border/30 text-text-muted cursor-not-allowed'
: 'border-neon-pink text-neon-pink hover:bg-neon-pink/10'"
:disabled="testLoading || !testUrl"
@click="runWebhookTest"
>
{{ testLoading ? 'TESTING...' : 'SEND TEST' }}
</button>
</div>
<!-- Test result -->
<div v-if="testResult" class="mt-4 space-y-3">
<div class="flex items-center gap-2">
<span
class="px-2 py-0.5 text-[9px] font-display font-bold uppercase tracking-wider border"
:class="testResult.success
? 'border-green-400/50 text-green-400 bg-green-400/10'
: 'border-red-400/50 text-red-400 bg-red-400/10'"
>
{{ testResult.success ? 'PASS' : 'FAIL' }}
</span>
<span v-if="testResult.elapsed" class="font-mono text-text-muted text-[10px]">
{{ testResult.elapsed }}ms
</span>
<span v-if="testResult.correct === true" class="font-mono text-green-400 text-[10px]">CORRECT</span>
<span v-if="testResult.correct === false" class="font-mono text-red-400 text-[10px]">WRONG ANSWER</span>
</div>
<div v-if="testResult.error" class="bg-bg p-3 border border-red-400/30">
<p class="font-mono text-red-400 text-xs">{{ testResult.error }}</p>
</div>
<div v-if="testResult.payload" class="bg-bg p-3">
<p class="text-[9px] font-display font-bold text-text-muted uppercase tracking-wider mb-1">SENT</p>
<pre class="text-[10px] font-mono text-neon-cyan/70 overflow-x-auto">{{ JSON.stringify(testResult.payload, null, 2) }}</pre>
</div>
<div v-if="testResult.response" class="bg-bg p-3">
<p class="text-[9px] font-display font-bold text-text-muted uppercase tracking-wider mb-1">RECEIVED</p>
<pre class="text-[10px] font-mono text-neon-pink/70 overflow-x-auto">{{ JSON.stringify(testResult.response, null, 2) }}</pre>
</div>
</div>
</div>
<!-- Test endpoints -->
<div
<div v-if="docs"
v-for="(test, key) in docs.testing"
:key="key"
class="border-2 border-border bg-surface p-5"
@@ -699,7 +932,7 @@ const registrationTest = `{
</div>
<!-- Tips -->
<div class="border-2 border-neon-cyan/20 bg-neon-cyan/5 p-5">
<div v-if="docs" class="border-2 border-neon-cyan/20 bg-neon-cyan/5 p-5">
<h3 class="font-display font-bold text-sm text-neon-cyan tracking-wider mb-4">
TIPS
</h3>