Via tools/grade_run.py against LM Studio (load -> all prompts -> unload -> verify).
kat-coder: lfu/tts/webhook/automation/rust (lfu has a real SyntaxError: 'self._ bump_freq')
qwen3-coder-30b: lfu/tts/webhook/automation/rust (all 4 py parse clean; terse ~2k tok outputs)
Grading deferred to a later session (capture-only mode).
Script hardening:
- --resident / --unload-all commands (read loaded_instances, POST unload, verify)
- MEMORY GUARD: aborts if a different model is resident (never stack 30GB models)
- TTFT self-discovery dump (LM Studio returns empty stats non-streaming;
fix next session: switch to /api/v1/chat stream:true -> chat.end result.stats)
Co-Authored-By: Claude <noreply@anthropic.com>
192 lines
6.0 KiB
Python
192 lines
6.0 KiB
Python
import asyncio
|
|
import hashlib
|
|
import hmac
|
|
import json
|
|
import time
|
|
from collections import defaultdict, deque
|
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
from urllib.parse import urlparse
|
|
import threading
|
|
|
|
# Configuration
|
|
SHARED_SECRET = b"my_secret_key"
|
|
DISCORD_WEBHOOK_URL = "https://discord.com/api/webhooks/1234567890/test"
|
|
MAX_DISCORD_RATE = 5 # events per second
|
|
RATE_LIMIT_WINDOW = 1.0 # seconds
|
|
|
|
# In-memory stores
|
|
idempotency_store = {} # event_id -> timestamp
|
|
discord_forward_count = 0
|
|
discord_forward_times = deque(maxlen=MAX_DISCORD_RATE) # timestamps of forwards
|
|
|
|
# Token bucket for rate limiting
|
|
bucket_tokens = MAX_DISCORD_RATE
|
|
last_refill = time.time()
|
|
bucket_lock = threading.Lock()
|
|
|
|
def verify_signature(body, signature):
|
|
"""Verify HMAC signature of the request body."""
|
|
expected = hmac.new(SHARED_SECRET, body, hashlib.sha256).hexdigest()
|
|
return hmac.compare_digest(signature, expected)
|
|
|
|
def is_idempotent(event_id):
|
|
"""Check if event has been seen recently."""
|
|
now = time.time()
|
|
if event_id in idempotency_store:
|
|
if now - idempotency_store[event_id] < 300: # 5 minutes
|
|
return True
|
|
idempotency_store[event_id] = now
|
|
return False
|
|
|
|
def rate_limit():
|
|
"""Check if we can make a Discord forward."""
|
|
global bucket_tokens, last_refill
|
|
with bucket_lock:
|
|
now = time.time()
|
|
# Refill tokens based on time passed
|
|
elapsed = now - last_refill
|
|
if elapsed > RATE_LIMIT_WINDOW:
|
|
bucket_tokens = min(MAX_DISCORD_RATE, bucket_tokens + elapsed / RATE_LIMIT_WINDOW * MAX_DISCORD_RATE)
|
|
last_refill = now
|
|
if bucket_tokens >= 1:
|
|
bucket_tokens -= 1
|
|
return True
|
|
return False
|
|
|
|
async def discord_send(payload):
|
|
"""Simulate sending to Discord webhook."""
|
|
# Simulate occasional 429
|
|
import random
|
|
if random.random() < 0.05: # 5% chance of 429
|
|
retry_after = random.randint(1, 3)
|
|
raise Exception(f"HTTP 429: Retry-After {retry_after}")
|
|
# Simulate success
|
|
return True
|
|
|
|
class WebhookHandler(BaseHTTPRequestHandler):
|
|
def do_POST(self):
|
|
if self.path != "/webhook":
|
|
self.send_response(404)
|
|
self.end_headers()
|
|
return
|
|
|
|
# Read body
|
|
content_length = int(self.headers.get('Content-Length', 0))
|
|
if not content_length:
|
|
self.send_response(400)
|
|
self.end_headers()
|
|
return
|
|
|
|
body = self.rfile.read(content_length)
|
|
signature = self.headers.get('X-Signature')
|
|
if not signature:
|
|
self.send_response(401)
|
|
self.end_headers()
|
|
return
|
|
|
|
# Verify signature
|
|
if not verify_signature(body, signature):
|
|
self.send_response(401)
|
|
self.end_headers()
|
|
return
|
|
|
|
try:
|
|
data = json.loads(body)
|
|
except json.JSONDecodeError:
|
|
self.send_response(400)
|
|
self.end_headers()
|
|
return
|
|
|
|
event_id = data.get("event_id")
|
|
if not event_id:
|
|
self.send_response(400)
|
|
self.end_headers()
|
|
return
|
|
|
|
# Check idempotency
|
|
if is_idempotent(event_id):
|
|
self.send_response(200)
|
|
self.end_headers()
|
|
return
|
|
|
|
# Forward to Discord
|
|
asyncio.run(self.forward_to_discord(data))
|
|
self.send_response(200)
|
|
self.end_headers()
|
|
|
|
async def forward_to_discord(self, data):
|
|
"""Forward event to Discord with rate limiting and retries."""
|
|
# Rate limit check
|
|
while not rate_limit():
|
|
await asyncio.sleep(0.1)
|
|
|
|
# Prepare payload for Discord
|
|
summary = {
|
|
"content": f"Event {data['type']}: {data.get('data', {}).get('message', 'No message')}"
|
|
}
|
|
|
|
retry_after = 0
|
|
while True:
|
|
try:
|
|
await discord_send(summary)
|
|
break
|
|
except Exception as e:
|
|
if "HTTP 429" in str(e):
|
|
# Extract retry-after
|
|
import re
|
|
match = re.search(r"Retry-After (\d+)", str(e))
|
|
if match:
|
|
retry_after = int(match.group(1))
|
|
else:
|
|
retry_after = 1
|
|
await asyncio.sleep(retry_after)
|
|
else:
|
|
# Log error but don't fail silently
|
|
print(f"Discord send failed: {e}")
|
|
break
|
|
|
|
if __name__ == "__main__":
|
|
# Run tests
|
|
import unittest
|
|
import threading
|
|
import time
|
|
|
|
class TestWebhookBridge(unittest.TestCase):
|
|
def setUp(self):
|
|
self.handler = WebhookHandler.__new__(WebhookHandler)
|
|
self.handler.path = "/webhook"
|
|
self.handler.headers = {}
|
|
self.handler.rfile = None
|
|
self.handler.wfile = None
|
|
|
|
def test_signature_verification(self):
|
|
body = b'{"event_id": "123", "type": "chat", "data": {}}'
|
|
signature = hmac.new(SHARED_SECRET, body, hashlib.sha256).hexdigest()
|
|
self.assertTrue(verify_signature(body, signature))
|
|
# Tampered signature
|
|
self.assertFalse(verify_signature(body, "wrong_signature"))
|
|
|
|
def test_idempotency(self):
|
|
event_id = "test_event"
|
|
# First time - should not be idempotent
|
|
self.assertFalse(is_idempotent(event_id))
|
|
# Second time - should be idempotent
|
|
self.assertTrue(is_idempotent(event_id))
|
|
|
|
def test_rate_limiting(self):
|
|
# Fill bucket
|
|
for _ in range(MAX_DISCORD_RATE):
|
|
self.assertTrue(rate_limit())
|
|
# Next should fail
|
|
self.assertFalse(rate_limit())
|
|
|
|
# Run tests
|
|
unittest.main(argv=[''], exit=False, verbosity=2)
|
|
|
|
# Start HTTP server
|
|
server = HTTPServer(('localhost', 8080), WebhookHandler)
|
|
print("Starting server on http://localhost:8080")
|
|
try:
|
|
server.serve_forever()
|
|
except KeyboardInterrupt:
|
|
print("\nShutting down...") |