Files
wyuc bb8d4f30e7 feat(chat): add experimental Pi classroom runtime behind a flag (#914)
* feat(chat): add experimental Pi classroom runtime

* fix(chat): harden Pi whiteboard action sequencing

* style(chat): format session retirement flow

* style(playback): format async scene transition

* fix(chat): retire actions on session errors

* fix(chat): close Pi runtime lifecycle gaps

* fix(chat): avoid replaying historical whiteboard actions

* fix(chat): prevent Pi structured-output residue from leaking and inflating turns

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(chat): expose whiteboard element/line ids and bound code-line context

Surface each element's id (and code line ids) in the Pi whiteboard context so
later child agents can target wb_delete / wb_edit_code, and cap the rendered
code lines with a shared character budget so a code-heavy board cannot grow the
prompt without bound. Return only the current turn's whiteboard ledger from the
Pi director loop instead of carrying history forward across requests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(chat): bound Pi whiteboard code context

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(chat): prioritize newer persisted whiteboard code in budget

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(chat): enforce whiteboard boundaries across Pi sessions

* feat(chat): refine soft-closing discussion controls

* fix(chat): make whiteboard clearing model-directed

---------

Co-authored-by: apple <apple@GigideMacBook-Air.local>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: LING-6150 <duan.lin@northeastern.edu>
2026-07-17 11:22:02 +08:00

280 lines
9.9 KiB
Bash

# =============================================================================
# OpenMAIC Environment Variables
# Copy this file to .env.local and fill in the values you need.
# All variables are optional — only configure the providers you want to use.
# You can also use server-providers.yml for configuration (see docs).
# =============================================================================
# --- LLM Providers -----------------------------------------------------------
# Format: {PROVIDER}_API_KEY, {PROVIDER}_BASE_URL (optional), {PROVIDER}_MODELS (optional, comma-separated)
OPENAI_API_KEY=
OPENAI_BASE_URL=
OPENAI_MODELS=
# Azure uses deployment names as model IDs.
AZURE_OPENAI_API_KEY=
AZURE_OPENAI_BASE_URL=https://YOUR-RESOURCE.openai.azure.com/openai
AZURE_OPENAI_MODELS=
ANTHROPIC_API_KEY=
ANTHROPIC_BASE_URL=
ANTHROPIC_MODELS=
GOOGLE_API_KEY=
GOOGLE_BASE_URL=
GOOGLE_MODELS=
DEEPSEEK_API_KEY=
DEEPSEEK_BASE_URL=
# Example: deepseek-v4-pro,deepseek-v4-flash
DEEPSEEK_MODELS=
QWEN_API_KEY=
QWEN_BASE_URL=
QWEN_MODELS=
KIMI_API_KEY=
KIMI_BASE_URL=
KIMI_MODELS=
MINIMAX_API_KEY=
# MiniMax Anthropic-compatible endpoint for the built-in Anthropic SDK integration
MINIMAX_BASE_URL=https://api.minimaxi.com/anthropic/v1
# Example: MiniMax-M2.7-highspeed,MiniMax-M2.7,MiniMax-M2.5-highspeed,MiniMax-M2.5
MINIMAX_MODELS=
GLM_API_KEY=
GLM_BASE_URL=
GLM_MODELS=
SILICONFLOW_API_KEY=
SILICONFLOW_BASE_URL=
SILICONFLOW_MODELS=
DOUBAO_API_KEY=
DOUBAO_BASE_URL=
DOUBAO_MODELS=
OPENROUTER_API_KEY=
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
# Example: deepseek/deepseek-v4-pro,deepseek/deepseek-v4-flash
OPENROUTER_MODELS=
GROK_API_KEY=
GROK_BASE_URL=
GROK_MODELS=
TENCENT_API_KEY=
# Tencent TokenHub OpenAI-compatible endpoint. Hy3 is a model ID, not an env prefix.
# TENCENT_HUNYUAN_* is also accepted as an alias.
TENCENT_BASE_URL=https://tokenhub.tencentmaas.com/v1
# Example: hy3-preview,hunyuan-2.0-thinking-20251109,hunyuan-2.0-instruct-20251111
TENCENT_MODELS=
XIAOMI_API_KEY=
# MIMO_* is also accepted as an alias. Use tp-... keys only with Token Plan URLs.
XIAOMI_BASE_URL=https://api.xiaomimimo.com/v1
# Token Plan regional examples:
# XIAOMI_BASE_URL=https://token-plan-cn.xiaomimimo.com/v1
# XIAOMI_BASE_URL=https://token-plan-sgp.xiaomimimo.com/v1
# XIAOMI_BASE_URL=https://token-plan-ams.xiaomimimo.com/v1
# Example: mimo-v2.5-pro,mimo-v2-pro,mimo-v2.5,mimo-v2-omni,mimo-v2-flash
XIAOMI_MODELS=
# --- Ollama (Local Models) ---------------------------------------------------
# No API key needed. Configure BASE_URL here (server-side) so it bypasses SSRF
# protection automatically. Client-supplied localhost URLs are blocked in production.
# OLLAMA_BASE_URL=http://localhost:11434/v1
# OLLAMA_MODELS=llama3.3,llama3.2,qwen2.5,mistral,gemma3
# Lemonade local server (OpenAI-compatible, no API key required)
# LEMONADE_BASE_URL=http://localhost:13305/v1
# LEMONADE_MODELS=Qwen3-0.6B-GGUF,Llama-3.2-1B-Instruct-Hybrid,Qwen2.5-VL-7B-Instruct
# --- TTS (Text-to-Speech) ----------------------------------------------------
TTS_OPENAI_API_KEY=
TTS_OPENAI_BASE_URL=
TTS_AZURE_API_KEY=
TTS_AZURE_BASE_URL=
TTS_GLM_API_KEY=
TTS_GLM_BASE_URL=
TTS_QWEN_API_KEY=
TTS_QWEN_BASE_URL=
TTS_MINIMAX_API_KEY=
# MiniMax TTS endpoint (speech-2.8 / 2.6 / 02 / 01 series)
TTS_MINIMAX_BASE_URL=https://api.minimaxi.com
TTS_ELEVENLABS_API_KEY=
TTS_ELEVENLABS_BASE_URL=
# Lemonade TTS (local, no API key required)
# TTS_LEMONADE_BASE_URL=http://localhost:13305/v1
# --- ASR (Automatic Speech Recognition) --------------------------------------
ASR_OPENAI_API_KEY=
ASR_OPENAI_BASE_URL=
ASR_QWEN_API_KEY=
ASR_QWEN_BASE_URL=
ASR_AZURE_API_KEY=
ASR_AZURE_BASE_URL=https://{region}.api.cognitive.microsoft.com
# Lemonade ASR (local, WAV input only, no API key required)
# ASR_LEMONADE_BASE_URL=http://localhost:13305/v1
# --- PDF Processing -----------------------------------------------------------
PDF_UNPDF_API_KEY=
PDF_UNPDF_BASE_URL=
PDF_MINERU_API_KEY=
PDF_MINERU_BASE_URL=
# Optional. Defaults to "pipeline"; use "hybrid-auto-engine" only when your MinerU
# service has the required GPU/device configuration.
PDF_MINERU_BACKEND=
# --- Image Generation ---------------------------------------------------------
IMAGE_OPENAI_API_KEY=
IMAGE_OPENAI_BASE_URL=https://api.openai.com/v1
IMAGE_SEEDREAM_API_KEY=
IMAGE_SEEDREAM_BASE_URL=
IMAGE_QWEN_IMAGE_API_KEY=
IMAGE_QWEN_IMAGE_BASE_URL=
IMAGE_NANO_BANANA_API_KEY=
IMAGE_NANO_BANANA_BASE_URL=
IMAGE_MINIMAX_API_KEY=
# Example models: image-01, image-01-live
IMAGE_MINIMAX_BASE_URL=https://api.minimaxi.com
IMAGE_GROK_API_KEY=
IMAGE_GROK_BASE_URL=
# Lemonade image generation (local, no API key required)
# IMAGE_LEMONADE_BASE_URL=http://localhost:13305/v1
# --- Video Generation ---------------------------------------------------------
VIDEO_SEEDANCE_API_KEY=
VIDEO_SEEDANCE_BASE_URL=
VIDEO_KLING_API_KEY=
VIDEO_KLING_BASE_URL=
VIDEO_VEO_API_KEY=
VIDEO_VEO_BASE_URL=
VIDEO_SORA_API_KEY=
VIDEO_SORA_BASE_URL=
VIDEO_MINIMAX_API_KEY=
# Example models: MiniMax-Hailuo-2.3, MiniMax-Hailuo-2.3-Fast, MiniMax-Hailuo-02
VIDEO_MINIMAX_BASE_URL=https://api.minimaxi.com
VIDEO_GROK_API_KEY=
VIDEO_GROK_BASE_URL=
VIDEO_HAPPYHORSE_API_KEY=
VIDEO_HAPPYHORSE_BASE_URL=https://dashscope.aliyuncs.com
# --- Web Search ---------------------------------------------------------------
# Note: Grok (xAI) web search is available via chat completions + search tools,
# not as a standalone search API. Use Grok LLM provider with search_parameters
# in chat requests. See: https://docs.x.ai/docs/guides/tools/search-tools
TAVILY_API_KEY=
BOCHA_API_KEY=
BOCHA_BASE_URL=https://api.bocha.cn
BRAVE_API_KEY=
BAIDU_API_KEY=
BAIDU_BASE_URL=https://qianfan.baidubce.com
# Self-hosted SearXNG instance (no API key required)
SEARXNG_BASE_URL=
# Dedicated MiniMax web-search vars avoid conflicting with the LLM MINIMAX_* endpoint.
WEB_SEARCH_MINIMAX_API_KEY=
WEB_SEARCH_MINIMAX_BASE_URL=https://api.minimaxi.com
# --- Experimental Features ---------------------------------------------------
# Use the experimental Pi-based classroom chat runtime. Disabled by default.
# NEXT_PUBLIC_PI_CHAT_ENABLED=true
# --- Proxy (optional) --------------------------------------------------------
# HTTP_PROXY=
# HTTPS_PROXY=
# --- Misc ---------------------------------------------------------------------
# Server-side default model for API routes like /api/generate-classroom.
# Required for server-side stages (those that don't receive a client x-model):
# resolveModel throws if a stage resolves to no model (no MODEL_ROUTES entry, no
# x-model, no DEFAULT_MODEL) — there is intentionally no hardcoded vendor fallback.
# Example: anthropic:claude-3-5-haiku-20241022 or google:gemini-3-flash-preview
# OpenAI example: openai:gpt-5.5
# MiniMax example: minimax:MiniMax-M2.7-highspeed
DEFAULT_MODEL=
# Optional per-stage model routing (#745). A JSON object mapping a generation
# stage to a model string (`provider:model`). Resolution order for a stage:
# stage route > x-model (client) > DEFAULT_MODEL. A configured route is the
# operator's deliberate choice and wins even when the browser sends its saved
# model as x-model. Unset = identical to today (everything uses DEFAULT_MODEL).
# Unlisted stages fall back to x-model then DEFAULT_MODEL, so you can override
# just one or two and leave the rest to the client/default.
# Point a stage only at a server-configured provider (its key resolvable); a
# route to an unconfigured/invalid model fails at request time for that stage,
# the same way a bad DEFAULT_MODEL would (no startup validation).
# Routable stages: scene-outlines-stream, scene-content, scene-actions,
# agent-profiles, quiz-grade, pbl-chat, chat-adapter, generate-classroom,
# web-search-query-rewrite.
# scene-content can also be routed per scene type with composite keys:
# scene-content:slide, scene-content:quiz, scene-content:interactive,
# scene-content:pbl. A type falls back to the base scene-content route when it
# has no key of its own (so scene-content:<type> > scene-content > x-model >
# DEFAULT_MODEL).
# A route value can be a model string, OR an object {"model","thinking"} where
# `thinking` is the full ThinkingConfig: mode (default|disabled|enabled|auto),
# effort (none|minimal|low|medium|high|xhigh|max), level (minimal|low|medium|
# high, Gemini), enabled (bool), budgetTokens (number), excludeReasoningOutput
# (bool). It is normalized per the model's capability. When a stage is routed:
# a set `thinking` wins over the client's thinking; with no `thinking` the routed
# model uses its own default and the client's thinking is dropped. Unrouted
# stages keep the client thinking.
# Example: cheap default, stronger model only for the heavy/conversational stages:
# MODEL_ROUTES='{"scene-content":"openai:gpt-5.4","scene-actions":"openai:gpt-5.4","pbl-chat":"anthropic:claude-sonnet-4","chat-adapter":"anthropic:claude-sonnet-4"}'
# Example: per scene type + pinned thinking (qwen budget, deepseek off):
# MODEL_ROUTES='{"scene-content:interactive":{"model":"qwen:qwen3.7-plus","thinking":{"enabled":true,"budgetTokens":8000}},"scene-content:quiz":{"model":"deepseek:deepseek-v4-pro","thinking":{"enabled":false}}}'
# MODEL_ROUTES=
# LOG_LEVEL=info
# LOG_FORMAT=pretty
# LLM_THINKING_DISABLED=false
# Opt-in parallel scene-content generation (#572). 0/unset = serial (default).
# A value > 1 fetches scene content concurrently (capped at 10); actions + TTS
# stay serial. Leave off if your API key has a low per-key concurrency quota.
# PARALLEL_SCENE_CONCURRENCY=3
# --- Local/Self-hosted Deployment ---------------------------------------------
# Set to "true" to allow private/local network URLs (e.g. localhost, 192.168.x.x).
# Required for self-hosted models like Ollama. Do NOT enable on public deployments.
# ALLOW_LOCAL_NETWORKS=true
# --- Access Control -----------------------------------------------------------
# Set a password to restrict site access. When set, users must enter this code
# before using the app. Leave empty or remove to disable access control.
# ACCESS_CODE=your-secret-code