chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:39:12 +08:00
commit d8dcd5f6d1
8604 changed files with 2479390 additions and 0 deletions
+212
View File
@@ -0,0 +1,212 @@
---
title: "Playground Studio"
version: 3.8.40
lastUpdated: 2026-06-28
---
# Playground Studio
> **Feature:** Playground Studio — unified AI testing workspace for `/dashboard/playground`.
> **Plans:** `17-playground-studio-redesign.plan.md` + `_orchestration/master-plan-group-C.md`
> **Status:** Released in v3.8.6
---
## Overview
Playground Studio transforms `/dashboard/playground` from a simple Monaco-based editor into
a full-featured testing workspace. It replaces the legacy `page.tsx` with a `PlaygroundStudio`
shell that renders four tabs and a shared config pane.
```
┌ Playground ──────────────────────────────────────────────────────────┐
│ [💬 Chat] [⚖ Compare] [{} API] [🔧 Build] 142↑ 38↓ · $0.002 </>│
├──────────────────────────────────────────┬───────────────────────────┤
│ {active tab content} │ ─ Config │
│ │ Endpoint [chat ] │
│ │ Model [gpt-5.4 ] │
│ │ System [textarea] │
│ │ Temp ▕▕▔▔ 0.7 │
│ │ Presets [▾ load][save] │
│ │ [✨ Improve prompt] │
└──────────────────────────────────────────┴───────────────────────────┘
```
---
## Tabs
### Chat Tab
Evolves `ChatPlayground.tsx` into a multi-turn streaming workbench:
- Full markdown rendering via `MarkdownMessage.tsx` (code blocks, tables, lists, links).
- System prompt sourced from the shared Config pane.
- Token/cost per message (prompt + completion tokens).
- Regenerate last response.
- Sends to `POST /v1/chat/completions` with SSE streaming.
### Compare Tab
The key differentiator for a proxy: run 1 prompt across up to **4 models in parallel**.
- Up to 4 columns, each independently streaming from `/v1/chat/completions`.
- `+ Add model` button (Cmd+K shortcut) to add columns.
- `Run all ▶` triggers all streams simultaneously via `Promise.all` + per-column `AbortController`.
- Global **Cancel all** aborts every in-flight stream.
- Per-column `ProviderMetrics` shows TTFT, TPS, tokens, and estimated cost in real time.
- Metrics labelled **"client-side estimate"** (D12) — measured from first SSE chunk.
### API Tab
Preserves 100% of the original Monaco editor for power users (D14):
- 10 endpoints: chat completions, completions, embeddings, images, audio, speech, transcriptions, moderations, rerank, search.
- Multimodal file upload.
- SSE streaming with real-time output.
- Wrapped as `ApiTab.tsx` (lazy-loaded, `ssr: false`).
### Build Tab
Tools/function calling and structured output UI:
- `ToolsBuilder.tsx` — add/edit/remove `tools[]` with JSON schema editor per tool.
Validates parameters via `ToolDefinitionSchema` (Zod).
- `StructuredOutputEditor.tsx` — toggle JSON mode + JSON schema editor.
Validates response against schema via `StructuredOutputSchema` (Zod).
- Sends request to `/v1/chat/completions` with `tools[]` and/or `response_format`.
---
## Config Pane (Shared)
`StudioConfigPane.tsx` — always visible, collapsible.
| Field | Component | Notes |
| -------------- | --------------------- | ---------------------------------------------------------------------- |
| Endpoint | `<select>` | 10 options matching `PlaygroundEndpoint` |
| Model | `<input>` | free text, e.g. `openai/gpt-4o` |
| System prompt | `<textarea>` | fed into all tabs |
| Parameters | `ParamSliders` | temperature, max_tokens, top_p, presence/frequency penalty, seed, stop |
| Presets | `PresetPicker` | load/save named config snapshots (persisted in DB) |
| Improve prompt | `ImprovePromptButton` | opens quota-warning modal, calls `/api/playground/improve-prompt` |
State is lifted to `PlaygroundStudio.tsx` and passed down to all tabs. Switching tabs
preserves config state.
---
## Top Bar
`StudioTopBar.tsx`:
- Tab switcher (role="tablist").
- `TokenCostCounter` — live token (↑/↓) and estimated cost display.
- Export code button (`</>`) — opens `ExportCodeModal`.
---
## Export Code Modal
`ExportCodeModal.tsx` uses `codeExport.ts` to generate curl / Python / TypeScript snippets
from the current `PlaygroundState`. API key placeholder is always `$OMNIROUTE_API_KEY` (D11).
---
## Prompt Improver
`ImprovePromptButton.tsx``useImprovePrompt.ts``POST /api/playground/improve-prompt`:
1. Modal warns "will consume quota".
2. On confirm, sends `{ system, prompt, model, tone }` to the route.
3. Route calls `/v1/chat/completions` internally with `promptImprover.META_SYSTEM_PROMPT`.
4. Returns `{ improvedSystem?, improvedPrompt?, tokensIn, tokensOut }`.
5. UI patches the Config pane system prompt and the Chat tab user prompt.
---
## Presets
`PresetPicker.tsx``usePresets.ts``/api/playground/presets/*`:
- Stored in `playground_presets` SQLite table (migration `084_playground_presets.sql`).
- Each preset stores: `name`, `endpoint`, `model`, `system`, `params_json`, `created_at`.
- CRUD: `GET` list, `POST` create, `GET /:id`, `PUT /:id`, `DELETE /:id`.
---
## Stream Metrics
`useStreamMetrics.ts` + `streamMetrics.ts` (pure function):
- `start()` — records request start time.
- `onFirstChunk()` — records TTFT.
- `onChunk(n)` — accumulates completion token count.
- `finish(usage?)` — computes final metrics: `ttftMs`, `totalMs`, `tps`, `tokensIn`, `tokensOut`, `costUsd`.
- Pricing from static table in `src/lib/playground/types.ts` (labelled "estimated" — D13).
---
## Backend Routes
| Method | Path | Handler |
| -------- | -------------------------------- | ----------------------------------------------------------------------------------------- |
| `POST` | `/api/playground/improve-prompt` | Zod-validates `ImprovePromptRequestSchema`; calls `/v1/chat/completions` with meta-prompt |
| `GET` | `/api/playground/presets` | Returns `{ presets: PlaygroundPresetListItem[] }` |
| `POST` | `/api/playground/presets` | Creates preset; validates `PlaygroundPresetCreateSchema` |
| `GET` | `/api/playground/presets/:id` | Returns one preset or 404 |
| `PUT` | `/api/playground/presets/:id` | Partial update |
| `DELETE` | `/api/playground/presets/:id` | 204 |
Auth: optional (`REQUIRE_API_KEY`). Errors via `buildErrorBody()` (Hard Rule #12).
---
## Key Files
| Path | Purpose |
| -------------------------------------------------------------------------- | --------------------------------------------------- |
| `src/app/(dashboard)/dashboard/playground/PlaygroundStudio.tsx` | Shell component, tab orchestrator |
| `src/app/(dashboard)/dashboard/playground/components/StudioTopBar.tsx` | Tabs + counter + export button |
| `src/app/(dashboard)/dashboard/playground/components/StudioConfigPane.tsx` | Shared config panel |
| `src/app/(dashboard)/dashboard/playground/components/tabs/ChatTab.tsx` | Chat workbench |
| `src/app/(dashboard)/dashboard/playground/components/tabs/CompareTab.tsx` | Multi-model compare |
| `src/app/(dashboard)/dashboard/playground/components/tabs/ApiTab.tsx` | Monaco editor (preserved) |
| `src/app/(dashboard)/dashboard/playground/components/tabs/BuildTab.tsx` | Tools + structured output |
| `src/app/(dashboard)/dashboard/playground/components/ExportCodeModal.tsx` | Code export modal |
| `src/app/(dashboard)/dashboard/playground/components/CompareColumn.tsx` | Single compare column |
| `src/app/(dashboard)/dashboard/playground/components/ProviderMetrics.tsx` | TTFT/TPS display |
| `src/app/(dashboard)/dashboard/playground/hooks/useStreamMetrics.ts` | Client-side metric hook |
| `src/app/(dashboard)/dashboard/playground/hooks/usePresets.ts` | Presets CRUD hook |
| `src/app/(dashboard)/dashboard/playground/hooks/useImprovePrompt.ts` | Improve-prompt hook |
| `src/lib/playground/codeExport.ts` | curl/Python/TS generator (shared with Search Tools) |
| `src/lib/playground/promptImprover.ts` | Meta-prompt builder |
| `src/lib/playground/streamMetrics.ts` | Pure metrics computation |
| `src/lib/db/playgroundPresets.ts` | DB module (CRUD) |
| `src/app/api/playground/improve-prompt/route.ts` | Improve-prompt REST route |
| `src/app/api/playground/presets/route.ts` | Presets list + create |
| `src/app/api/playground/presets/[id]/route.ts` | Presets get/update/delete |
| `src/lib/db/migrations/084_playground_presets.sql` | DB migration |
---
## Troubleshooting
| Symptom | Cause | Fix |
| -------------------------------------- | ----------------------------- | ------------------------------------------------------------------------------- |
| Monaco editor not rendering in API tab | SSR loaded Monaco | Verify `ApiTab` uses `dynamic(..., { ssr: false })` |
| Compare streams fire sequentially | Wrong `Promise.all` usage | All stream starts must be dispatched in one `Promise.all` call |
| Metrics show `null` TTFT | First chunk handler not wired | Check `useStreamMetrics.onFirstChunk()` is called in the SSE reader loop |
| Preset not persisting | DB migration not run | Run `npm run db:migrate` or restart the server (migration auto-runs on startup) |
| Improve prompt returns 502 | Model not set in Config | User must enter a model name in the Config pane before improving |
| Export code shows `MISSING_API_KEY` | Placeholder not inserted | `codeExport.ts` always uses `API_KEY_PLACEHOLDER = "$OMNIROUTE_API_KEY"` |
---
## References
- Master plan: `_tasks/features-v3.8.6/refactorpages/_orchestration/master-plan-group-C.md`
- Feature plan: `_tasks/features-v3.8.6/refactorpages/17-playground-studio-redesign.plan.md`
- Code export: `src/lib/playground/codeExport.ts`
- Prompt improver: `src/lib/playground/promptImprover.ts`
- Search Tools Studio: `docs/frameworks/SEARCH_TOOLS_STUDIO.md`