Skip to main content
POST

Dual Chat (Arena Mode) Stable

Send a prompt to two AI models simultaneously. Models respond in parallel, and responses are returned anonymized for blind comparison.

Authentication Required

JWT Claims Extraction (Lines 338-350):

Request Body

string
required
User message sent to both modelsValidation (Line 200):
string
Model selection strategyValues:
  • "random": Two different random active models (Lines 246-249)
  • "topper": Top-performing model + random model (Lines 237-242)
  • Default if manual models provided: "manual" (Line 233)
Selection Logic:
string
First model name (manual selection)Validation (Lines 218-229):
Required: Only if model2 also provided
string
Second model name (manual selection)Required: Only if model1 also provided
string
System prompt applied to both modelsDefault: Implementation-defined and not guaranteed (provider-specific)
integer
Maximum tokens per model responseApplies: To both models independently
number
Sampling temperature (0.0-2.0) for both modelsDefault: Not specified by API contract (provider-defined)
string
Session tracking identifierAuto-generation (Line 197):
string
Thread UUID to associate comparison with conversationValidation (Lines 354-360):

Response

boolean
Always true on success (Line 392)
object
First model response (same structure as single chat)
object
Second model response (same structure as agent1)
string
UUID identifying this comparison (Line 198, 395)Used for: Voting via /api/arena/model-vote
object
string
ISO8601 UTC timestamp (Line 415)
integer
Total request duration (Lines 265, 416)Note: Due to parallel execution, approximately equal to slowest model time

Side Effects

Database Mutations (Lines 333-360):
  1. message_logs table (Lines 333-334):
    • Two separate log entries (one per model)
  2. users table UPSERT (Lines 336-350):
    • Executes on every authenticated request
    • Idempotent operation
  3. comparisons table (Line 352):
    • Stores comparison data for voting/leaderboard
    • Links to both models
  4. thread_messages table (conditional, Lines 354-360):
    • Only if threadId provided and valid GUID
    • Links message to comparison via comparisonId

Behavior

Parallel Execution (Lines 254-257):
Independence:
  • Each model has independent 45s timeout
  • Each model has independent fallback chain
  • One model failure doesn’t block the other
Response Time (Line 265):
  • Measures total elapsed time
  • Due to parallel execution: max(model1_time, model2_time) + overhead
Selection Modes (Lines 213-251): Topper Mode Implementation (Lines 239-241):
  • Queries model_votes table for highest win rate
  • Pairs top model with random model
  • Ensures diverse comparison
Arena Comparison Logic (Lines 362-388):

Error Conditions

Nested Exception Handling (Lines 421-443):
Partial Execution: If one model succeeds and one fails, both tasks still complete. Full dual response returned if both succeed. If either fails, exception bubbles to error handler.

Edge Cases

  1. Same model selected twice: Not prevented by code, allowed in random selection
  2. Topper mode with insufficient vote data: Behavior not enforced by server contract (assumed fallback to random selection)
  3. Invalid threadId GUID: Silently skipped, no error (Line 356 guard)
  4. Model fallback changes model names: finalModel1 and finalModel2 may differ from requested models
  5. Null usage stats: Handled with null-coalescing (Lines 366-367)

Comparison ID Usage

Generated at request start (Line 198):
Used for:
  1. Logging comparison to comparisons table (Line 352)
  2. Linking to thread message in thread_messages table (Line 358)
  3. Returned in response for voting (Line 395)
  4. Voting endpoint requires this ID: POST /api/arena/model-vote

Rate Limits

No explicit rate limiting in controller. Provider-level limits apply:
  • Groq free tier: 30 req/min, 14,400 tokens/min
  • Dual chat consumes 2× tokens (both models)
  • Effective limit: ~15 dual-chat requests/min on free tier