# ============================================================================= # 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= # For relays whose non-streaming Chat Completions response is incompatible. # Forces custom OpenAI base URLs to use Chat Completions and buffers SSE responses. # Has no effect on the official OpenAI base URL. Disabled by default. # OPENAI_COMPAT_USE_STREAMING_CHAT=true # 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= ATLASCLOUD_API_KEY= ATLASCLOUD_BASE_URL=https://api.atlascloud.ai/v1 # Example: qwen/qwen3.5-flash,deepseek-ai/deepseek-v4-pro ATLASCLOUD_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= # Example: grok-4.6,grok-4.5 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 # Amazon Bedrock LLMs (no OpenAI-style API key required) # Set BEDROCK_REGION to enable Bedrock server-side provider config. # AWS credentials are resolved from the standard AWS environment / credential chain. # BEDROCK_REGION=us-east-1 # BEDROCK_MODELS=us.anthropic.claude-sonnet-5,us.anthropic.claude-opus-4-8 # Optional bearer-token authentication or custom Bedrock-compatible endpoint. # AWS_BEARER_TOKEN_BEDROCK= # BEDROCK_API_KEY= # BEDROCK_BASE_URL= # DEFAULT_MODEL=bedrock:us.anthropic.claude-sonnet-5 # --- 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= # Qwen voice cloning reuses TTS_QWEN_API_KEY. Override the target model if needed. # TTS_QWEN_VOICE_CLONE_MODEL=qwen3-tts-vc-2026-01-22 TTS_DOUBAO_API_KEY= TTS_DOUBAO_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= # VoxCPM2 TTS (local, OpenAI-compatible; API key is optional) # TTS_VOXCPM_API_KEY= # TTS_VOXCPM_BASE_URL=http://localhost:8000/v1 # Lemonade TTS (local, no API key required) # TTS_LEMONADE_BASE_URL=http://localhost:13305/v1 # Operators can force-disable any built-in TTS provider. Examples: # TTS_OPENAI_ENABLED=false # TTS_BROWSER_NATIVE_ENABLED=false # --- 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 # FunASR (local, WAV input only, no API key required) # ASR_FUNASR_BASE_URL=http://localhost:8000/v1 # Lemonade ASR (local, WAV input only, no API key required) # ASR_LEMONADE_BASE_URL=http://localhost:13305/v1 # Operators can force-disable any built-in ASR provider. Examples: # ASR_OPENAI_ENABLED=false # ASR_BROWSER_NATIVE_ENABLED=false # Optional local audio/video material extraction uses the first enabled server # ASR provider above. It also requires the system `ffmpeg` and `ffprobe` # executables on PATH; no bundled binary or npm dependency is installed. # Without both executables, OpenMAIC skips the local extractor and uses a # configured AliDocMind cloud extractor when available. With neither path # enabled, media materials fail cleanly with setup guidance. # --- 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= PDF_MINERU_CLOUD_API_KEY= PDF_MINERU_CLOUD_BASE_URL=https://mineru.net/api/v4 # Self-hosted MinerU never falls back to MinerU Cloud implicitly: a request that # selects self-hosted MinerU without a configured base URL fails loudly. Set this # to "true" to explicitly opt in to MinerU Cloud as a fallback (documents then # leave your infrastructure). Default: off. ALLOW_MINERU_CLOUD_FALLBACK= # AliDocMind uses an Alibaba Cloud AccessKey pair instead of a single API key. ALIDOCMIND_ACCESS_KEY_ID= ALIDOCMIND_ACCESS_KEY_SECRET= ALIDOCMIND_BASE_URL= # --- 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 # Operators can force-disable any built-in image provider, including the # client-only ComfyUI provider (it has no credential env). Examples: # IMAGE_OPENAI_ENABLED=false # IMAGE_COMFYUI_ENABLED=false # --- 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 # Operators can force-disable any built-in video provider. Examples: # VIDEO_GROK_ENABLED=false # VIDEO_KLING_ENABLED=false # --- 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= TAVILY_BASE_URL= BOCHA_API_KEY= BOCHA_BASE_URL=https://api.bocha.cn BRAVE_API_KEY= BRAVE_BASE_URL= 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 # Dedicated Doubao web-search vars avoid conflicting with the Doubao LLM provider. WEB_SEARCH_DOUBAO_API_KEY= WEB_SEARCH_DOUBAO_BASE_URL=https://open.feedcoopapi.com # Claude (Anthropic) native web search. Dedicated vars avoid conflicting with # ANTHROPIC_* LLM provider vars. Optional WEB_SEARCH_CLAUDE_MODELS pins the # search model server-side (first entry wins), e.g. claude-sonnet-5. WEB_SEARCH_CLAUDE_API_KEY= WEB_SEARCH_CLAUDE_BASE_URL=https://api.anthropic.com/v1 WEB_SEARCH_CLAUDE_MODELS= # Operators can force-disable any built-in web search provider. Examples: # TAVILY_ENABLED=false # WEB_SEARCH_DOUBAO_ENABLED=false # SEARXNG_ENABLED=false # Server-only, default-OFF selector for the Native Child execution harness. # OPENMAIC_ENABLE_PI_NATIVE_CHILD_RUNTIME=true # Server-only, default-OFF Native Spotlight capability; does not select the runtime. # OPENMAIC_ENABLE_PI_NATIVE_CHILD_SPOTLIGHT=true # --- Experimental Features --------------------------------------------------- # Boolean feature flags accept "true" or "1". NEXT_PUBLIC_* values are compiled # into the browser bundle at build time, so changing them requires a rebuild. # Enable the Pro workbench entry (the workbench also requires the agent # runtime to be configured server-side; see the Agent Runtime section). # Implies the MAIC Editor gate below — Pro mode always ships with the editor. # NEXT_PUBLIC_PRO_WORKBENCH_ENABLED=true # Master gate for the MAIC Editor Pro-mode entry point. Implied by # NEXT_PUBLIC_PRO_WORKBENCH_ENABLED; set it alone to enable the classroom # editor on a deployment without the workbench. # NEXT_PUBLIC_MAIC_EDITOR_ENABLED=true # Select @openmaic/editor inside Pro mode. This does not enable Pro mode by itself. # NEXT_PUBLIC_MAIC_EDITOR_RENDERER_ENABLED=true # Use @openmaic/renderer for the classroom playback canvas. # NEXT_PUBLIC_MAIC_PLAYBACK_RENDERER_ENABLED=true # Use the experimental Pi-based classroom chat runtime. Disabled by default. # NEXT_PUBLIC_PI_CHAT_ENABLED=true # Enable the server-side vocational task-engine generation path. # OPENMAIC_ENABLE_VOCATIONAL=true # Show the experimental vocational task-engine control in the client. # NEXT_PUBLIC_SHOW_VOCATIONAL_TEST_UI=true # Show the video export and PPTX import entry points. # NEXT_PUBLIC_ENABLE_VIDEO_EXPORT=true # NEXT_PUBLIC_ENABLE_PPTX_IMPORT=true # Informational destination shown on exported Quiz/PBL cover cards. Unset or # blank defaults to open.maic.chat; set to "off" to omit it. # NEXT_PUBLIC_VIDEO_EXPORT_CTA_DESTINATION=open.maic.chat # --- Agent Runtime (experimental) --------------------------------------------- # Server-only gate for durable background agent sessions: the /api/agent # session and owner-event control-plane routes plus the in-process session # runner. Default OFF — while disabled, every /api/agent/sessions* and # /api/agent/owner-events route answers 404. Truthy values are "true" or "1"; # anything else (including unset) is treated as disabled. # OPENMAIC_AGENT_RUNTIME_ENABLED=true # The runtime is server-backed and requires the PostgreSQL connection from the # "Server-backed Persistence" section below: without a non-empty DATABASE_URL # the runner never starts and the session store rejects requests, even with the # flag above enabled. # DATABASE_URL=postgres://openmaic:password@postgres:5432/openmaic # REQUIRED while the runtime is enabled: MODEL_ROUTES must explicitly route the # "maic-agent-driver" stage to a provider-prefixed model id. There is # intentionally no fallback — without this route every agent session fails at # run start. The route object must set api (or its alias dialect) to # "openai-completions" or "openai-responses"; any other value is rejected, and # a bare model id without a provider prefix is rejected too. Optional fields: # contextWindow pins the effective context window below the provider catalog # value (used by compaction thresholds), and thinking must never set effort # (the tool-using driver cannot combine reasoning_effort with function tools on # this transport). # MODEL_ROUTES='{"maic-agent-driver":{"model":"openai:gpt-5.5","api":"openai-completions"}}' # Runner tuning. Defaults are shown; only relevant once the runtime is enabled. # OPENMAIC_AGENT_RUNTIME_SCAN_INTERVAL_MS=1000 # OPENMAIC_AGENT_RUNTIME_HEARTBEAT_MS=2000 # OPENMAIC_AGENT_RUNTIME_LEASE_TTL_MS=10000 # OPENMAIC_AGENT_RUNTIME_MAX_CONCURRENT=2 # OPENMAIC_AGENT_RUNTIME_MAX_ATTEMPTS=5 # Global per-tool-call execution bound for every agent run (ms). A tool call # that neither resolves nor rejects within the budget is aborted and settles as # an error tool-result the agent can retry or proceed from; the session does # not die. Default 600000 (10 minutes). Tools with known longer budgets (media # synthesis, material extraction) carry their own explicit bounds in code. # OPENMAIC_AGENT_TOOL_TIMEOUT_MS=600000 # Conversation compaction is reserved and OFF by default. The reusable # compaction runtime is not implemented yet — it lands in a later slice of # work — and until then the runner runs without context transformation, so # these knobs are inert placeholders. # OPENMAIC_AGENT_COMPACTION_ENABLED=true # OPENMAIC_AGENT_COMPACTION_RESERVE_TOKENS=0 # OPENMAIC_AGENT_COMPACTION_KEEP_RECENT_TOKENS=0 # Session prompts and follow-up messages are capped server-side at a fixed # 100,000 characters; this limit is a constant and is not configurable. # --- Proxy (optional) -------------------------------------------------------- # HTTP_PROXY= # HTTPS_PROXY= # Comma-separated hosts that bypass the proxy. Supports domain suffixes and *. # NO_PROXY=localhost,127.0.0.1,.internal.example.com # --- 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 # Bedrock example: bedrock:us.anthropic.claude-sonnet-5 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. # At boot the server validates MODEL_ROUTES / DEFAULT_MODEL / _MODELS # and prints [config] warnings for unknown stages, unregistered providers, # providers with no API key, and bare model ids (which still default to openai # but are deprecated — write provider:model). Warnings only: the server starts # regardless, so a bad value is caught here instead of at request time. # Routable stages: scene-outlines-stream, scene-content, scene-actions, # agent-profiles, quiz-grade, pbl-chat, pbl-v2-runtime, chat-adapter, # generate-classroom, web-search-query-rewrite, maic-agent, # maic-agent-driver. # 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: > scene-content > x-model > # DEFAULT_MODEL). # pbl-v2-runtime follows the same composite fallback pattern with # pbl-v2-runtime:instructor, pbl-v2-runtime:open-task, pbl-v2-runtime:evaluate # and pbl-v2-runtime:simulator, falling back to the base pbl-v2-runtime route. # maic-agent-driver is REQUIRED when the agent runtime is enabled; see the # "Agent runtime (experimental)" section for its api/dialect constraints. # 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 # Build-time, space-separated CSP frame-ancestor sources in addition to 'self'. # Configure only origins you trust to embed OpenMAIC, then rebuild the app. The # Docker and Compose builds also accept this value as a build argument. # ALLOWED_FRAME_ANCESTORS=https://partner.example.com # Optional MP4 render service (issue #866). When set, the in-app "Export Video" # menu offers one-click MP4 rendering; when unset, it degrades to downloading a # project ZIP for local CLI rendering. Point this at the isolated render-service # container (see render-service/ and the "video-export" docker-compose profile). # This is operator-supplied trusted config: the app forwards uploads to it # without the SSRF guard, so a private/compose-network target works WITHOUT # setting ALLOW_LOCAL_NETWORKS. # RENDER_SERVICE_URL=http://render-service:9000 # Render-service-only opt-in for bounded local chunk execution. These variables # are read at runtime by the isolated render-service container; the public HTTP # API is unchanged. Defaults keep the existing in-process renderer. # RENDER_CHUNK_EXECUTION=false # RENDER_CHUNK_COUNT=1 # RENDER_CHUNK_WORKERS=1 # RENDER_MAX_PARALLEL_CHUNKS=1 # RENDER_CHUNK_SIZE_FRAMES=0 # RENDER_TARGET_CHUNK_FRAMES=0 # Honor x-forwarded-for / x-real-ip when deriving render-service client identity. # Enable only behind a trusted reverse proxy that overwrites these headers. # TRUST_PROXY_HEADERS=true # --- Server-backed Persistence ------------------------------------------------ # Build-time client switch and shared development token. The public token must # match PERSISTENCE_DEV_TOKEN. This development-only scheme provides no user # isolation and must not be used as public-production authentication. # NEXT_PUBLIC_PERSISTENCE=1 # NEXT_PUBLIC_PERSISTENCE_TOKEN= # Runtime PostgreSQL connection and matching development token. # DATABASE_URL=postgres://openmaic:password@postgres:5432/openmaic # PERSISTENCE_DEV_TOKEN= # Store asset bytes in S3 instead of PostgreSQL. Region, endpoint, and credentials # are resolved through the standard AWS SDK environment / credential chain. # ASSET_S3_BUCKET= # Opt into indirect asset byte egress: answer asset byte GETs with a short-lived # signed S3 URL (a 302, or a JSON descriptor for the packaged client) instead of # the bytes. Unset or "direct" keeps direct egress (the safe default). Requires # the object store's CORS to admit this app's origin and expose Content-Type, and # the signing identity to hold s3:ListBucket on the bucket so a missing key # answers 404 NoSuchKey rather than 403. # ASSET_BYTE_EGRESS=redirect # The asset collector is enabled by default when DATABASE_URL is configured. # ASSET_COLLECTION_ENABLED=true # ASSET_COLLECTION_INTERVAL_MS=900000 # ASSET_COLLECTION_GRACE_MS=3600000 # --- 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