# Root environment variables — Rust core, Tauri shell, and shared settings. # Copy to .env and fill in values as needed. # Loaded via: source scripts/load-dotenv.sh # # Tags: [required] must be set, [optional] has a sensible default or can be blank # --------------------------------------------------------------------------- # App environment # --------------------------------------------------------------------------- # [optional] App environment selector: production | staging. # Defaults to 'production' when unset. Uncomment and set to 'staging' to point # at the staging backend, use the ~/.openhuman-staging workspace, etc. # WARNING: staging uses a SEPARATE data directory (~/.openhuman-staging) from # production (~/.openhuman). Credentials, config, and auth profiles do NOT # carry over between environments. If you log in via the Tauri app in one # environment, the CLI running in the other will not see those credentials. # OPENHUMAN_APP_ENV=staging # --------------------------------------------------------------------------- # Backend API # --------------------------------------------------------------------------- # [optional] Primary backend URL (read by Rust core and QuickJS skills sandbox). # Defaults to https://api.tinyhumans.ai (production). Override here only if you # want a different backend (e.g. https://staging-api.tinyhumans.ai). # BACKEND_URL=https://api.tinyhumans.ai # [optional] Vite frontend mirrors — only required if you set OPENHUMAN_APP_ENV # above. Defaults are production. # VITE_OPENHUMAN_APP_ENV=staging # VITE_BACKEND_URL=https://staging-api.tinyhumans.ai # [optional] Consumer first-session UX in the desktop/web app (default off). See docs/plans/consumer-first-session-spec.md # VITE_CONSUMER_FIRST_SESSION=true # [optional] Chat attachments (image/video/document) master kill-switch. Enabled # by default; per-message modalities gated on the model's vision tier at runtime. # VITE_CHAT_ATTACHMENTS=false # --------------------------------------------------------------------------- # Authentication (for skills OAuth proxy and debug scripts) # --------------------------------------------------------------------------- # [optional] Session JWT — used by QuickJS skills sandbox for oauth.fetch proxy calls. # Also used by debug scripts (scripts/debug-skill.sh, scripts/debug-notion-live.sh). # Get from login flow or browser devtools. JWT_TOKEN= # --------------------------------------------------------------------------- # Core process # --------------------------------------------------------------------------- # [optional] Default: 127.0.0.1 (use 0.0.0.0 for Docker / cloud). # Leave unset to keep the default; the Docker image sets 0.0.0.0 automatically. # OPENHUMAN_CORE_HOST= # [optional] Extra CORS origins (comma-separated) allowed to reach the # JSON-RPC server. The Tauri webview and loopback hosts are always allowed. # For Docker / cloud deployments where the server binds to 0.0.0.0, add the # canonical frontend origin(s) here to prevent cross-origin abuse from # arbitrary sites (e.g. OPENHUMAN_CORE_ALLOWED_ORIGINS=https://app.example.com). # OPENHUMAN_CORE_ALLOWED_ORIGINS= # [optional] Default: 7788 OPENHUMAN_CORE_PORT=7788 # [optional] Default: http://127.0.0.1:7788/rpc OPENHUMAN_CORE_RPC_URL=http://127.0.0.1:7788/rpc # [optional] Comma-separated browser origins allowed to call /rpc with the # Authorization bearer. Tauri and loopback Vite origins are allowed by default. # Set this when serving a private web UI preview from a non-loopback origin. # OPENHUMAN_CORE_ALLOWED_ORIGINS=https://openhuman-ui.example.com # Core RPC bearer token. Single source of truth for /rpc auth. # - Tauri desktop: leave blank. The shell generates a fresh per-launch # bearer and hands it to the in-process core in-memory; nothing is # read from this variable. # - Docker / cloud / VPS: REQUIRED. Generate with `openssl rand -hex 32`. # Same value goes in the desktop's app/.env.local (or paste into the # first-run picker). See gitbooks/features/cloud-deploy.md. # - Standalone `openhuman core run` on a workstation: leave blank — the # core writes ${OPENHUMAN_WORKSPACE:-~/.openhuman}/core.token (0o600). # Use scripts/print-core-token.sh on the host to inspect the active token. # OPENHUMAN_CORE_TOKEN= # [optional] Run mode: child (default, spawns sidecar) | inprocess OPENHUMAN_CORE_RUN_MODE=child # [optional] Override path to openhuman core binary (leave blank for auto-detection) OPENHUMAN_CORE_BIN= # [optional] Explicit .env path for `openhuman serve` / `openhuman run` (loaded before the server starts). # Must be set in the parent environment (exported in your shell or service manager). It is read before # any dotenv file is loaded, so defining OPENHUMAN_DOTENV_PATH inside a .env file cannot select that file. # OPENHUMAN_DOTENV_PATH= # --------------------------------------------------------------------------- # Config overrides (override config.toml values at runtime) # --------------------------------------------------------------------------- # [optional] Local safety cap for side-effecting tool actions in a rolling hour (default 20). # Set to 0 to block all side-effecting tool actions entirely. OPENHUMAN_MAX_ACTIONS_PER_HOUR=20 # [optional] Default model to use OPENHUMAN_MODEL= # [optional] Workspace directory (default: ~/.openhuman or ~/.openhuman-staging when OPENHUMAN_APP_ENV=staging) # Leave commented out to use the default. Setting to empty string is treated as unset. # OPENHUMAN_WORKSPACE= # [optional] Default: 0.7 OPENHUMAN_TEMPERATURE=0.7 # [optional] Language for background LLM artifacts such as memory-tree summaries, # entity-extraction reasons, and learning reflections. Accepts UI locale tags # such as zh-CN or a language name. Leave unset for default behavior. # OPENHUMAN_OUTPUT_LANGUAGE=zh-CN # [optional] Operator override for the tool/agent action timeout, in seconds # (default 120, range 1-3600). When set to a valid value it overrides the # in-app "Action timeout" setting (Settings -> Agent OS access), which persists # to [agent].agent_timeout_secs. Leave unset to let the UI control it. # OPENHUMAN_TOOL_TIMEOUT_SECS= # [optional] Operator override for the inference HTTP request timeout, in # seconds (default 120, range 1-3600). Raise this when long reasoning/research # turns get cut off at the two-minute mark. Leave unset to use the default. # OPENHUMAN_INFERENCE_TIMEOUT_SECS= # [optional] Operator override for the inference HTTP connection-establishment # timeout, in seconds (default 10, range 1-300). Leave unset to use the default. # OPENHUMAN_INFERENCE_CONNECT_TIMEOUT_SECS= # [optional] Per-chunk streaming inactivity watchdog, in seconds (default 90, # range 1-3600). Aborts a stalled SSE response when NO token arrives for this # long and retries, so an upstream that flushes 200 then goes silent can't hang # a turn until OPENHUMAN_INFERENCE_TIMEOUT_SECS (which is often raised for long # research turns). The window resets on every token, so valid long responses are # never cut. Leave unset to use the default. # OPENHUMAN_INFERENCE_STREAM_IDLE_TIMEOUT_SECS= # [optional] Headless update restart contract: self_replace | supervisor # OPENHUMAN_AUTO_UPDATE_RESTART_STRATEGY=self_replace # [optional] Allow bearer-authenticated RPC callers to invoke update.apply/update.run # Disable on exposed server deployments unless you explicitly want remote self-upgrade. # OPENHUMAN_AUTO_UPDATE_RPC_MUTATIONS_ENABLED=true # --------------------------------------------------------------------------- # Runtime flags # --------------------------------------------------------------------------- # [optional] Default: 0 OPENHUMAN_BROWSER_ALLOW_ALL=0 # [optional] Default: 0 OPENHUMAN_LOG_PROMPTS=0 # [optional] Enable reasoning mode OPENHUMAN_REASONING_ENABLED= # [optional] Windows only: suppress the console window that flashes when the # shell tool spawns child processes (CREATE_NO_WINDOW). Default: false. # Equivalent TOML: [shell] hide_window = true OPENHUMAN_SHELL_HIDE_WINDOW= # [optional] Desktop CEF startup escape hatch. Set to 1/true/yes/on only when # CEF fails before the app can render, for example on a GPU/driver stack where # startup logs show `cef::initialize returned 0`. On Windows this pins CEF to the # pure-software ANGLE/SwiftShader GL backend (needed on NVIDIA Blackwell / # RTX 50-series, where bare --disable-gpu is insufficient — #4385); on other # platforms it adds --disable-gpu and --disable-gpu-compositing. Leave unset # otherwise; this disables hardware GPU acceleration and slows WebGL-heavy surfaces. # OPENHUMAN_DISABLE_GPU= # --------------------------------------------------------------------------- # Web search # --------------------------------------------------------------------------- # Web search is always enabled — no opt-in flag. Configure result budgets below. # [optional] Default: 5 OPENHUMAN_WEB_SEARCH_MAX_RESULTS=5 # [optional] Default: 10 OPENHUMAN_WEB_SEARCH_TIMEOUT_SECS=10 # --------------------------------------------------------------------------- # Seltz search (direct API — https://seltz.ai) # --------------------------------------------------------------------------- # [optional] API key from https://console.seltz.ai. When set, enables the # seltz_search agent tool. Fast (<200ms), independent index, domain/date filters. # SELTZ_API_KEY= # [optional] Override API base URL (default: https://api.seltz.ai/v1) # SELTZ_API_URL= # [optional] Default max results per query (1-20, default 10) # OPENHUMAN_SELTZ_MAX_RESULTS=10 # --------------------------------------------------------------------------- # Querit search (direct API — https://www.querit.ai) # --------------------------------------------------------------------------- # [optional] API key from https://www.querit.ai. Select "Querit" in # Settings > Search engine, or set OPENHUMAN_SEARCH_ENGINE=querit. # QUERIT_API_KEY= # OPENHUMAN_QUERIT_API_KEY= # --------------------------------------------------------------------------- # Brave search (direct API — https://brave.com/search/api/) # --------------------------------------------------------------------------- # [optional] API key from https://api.search.brave.com. Select "Brave" in # Settings > Search engine, or set OPENHUMAN_SEARCH_ENGINE=brave. Powers # web_search_tool plus brave_news_search / brave_image_search / # brave_video_search. Engine silently falls back to "managed" if no key # is present, so the agent always has working search. # BRAVE_API_KEY= # OPENHUMAN_BRAVE_API_KEY= # --------------------------------------------------------------------------- # Parallel search (direct API — https://parallel.ai) # --------------------------------------------------------------------------- # [optional] API key from https://parallel.ai. Select "Parallel" in # Settings > Search engine, or set OPENHUMAN_SEARCH_ENGINE=parallel. # Engine silently falls back to "managed" if no key is present. # PARALLEL_API_KEY= # OPENHUMAN_PARALLEL_API_KEY= # --------------------------------------------------------------------------- # SearXNG search (self-hosted — https://docs.searxng.org) # --------------------------------------------------------------------------- # [optional] Enable the searxng_search agent/MCP tool. Default: false. # OPENHUMAN_SEARXNG_ENABLED=false # [optional] Base URL for your SearXNG instance. Default: http://localhost:8080 # OPENHUMAN_SEARXNG_BASE_URL=http://localhost:8080 # [optional] Default max results per query (1-50, default 10) # OPENHUMAN_SEARXNG_MAX_RESULTS=10 # [optional] Default language when a tool call omits language. Default: en # OPENHUMAN_SEARXNG_DEFAULT_LANGUAGE=en # [optional] Request timeout in seconds. Default: 10 # OPENHUMAN_SEARXNG_TIMEOUT_SECONDS=10 # --------------------------------------------------------------------------- # Proxy # --------------------------------------------------------------------------- # [optional] Default: false OPENHUMAN_PROXY_ENABLED=false # [optional] HTTP proxy URL OPENHUMAN_HTTP_PROXY= # [optional] HTTPS proxy URL OPENHUMAN_HTTPS_PROXY= # [optional] Catch-all proxy URL OPENHUMAN_ALL_PROXY= # [optional] Comma-separated hosts to bypass proxy OPENHUMAN_NO_PROXY= # [optional] Proxy scope OPENHUMAN_PROXY_SCOPE= # [optional] Comma-separated services to proxy OPENHUMAN_PROXY_SERVICES= # --------------------------------------------------------------------------- # Local AI model tier # --------------------------------------------------------------------------- # [optional] Override selected model tier: low, medium, high # Applies the corresponding preset at config load time (overrides config.toml). OPENHUMAN_LOCAL_AI_TIER= # [optional] Override Ollama's HTTP server base URL (default: http://localhost:11434). # Useful when Ollama runs in another container, on another host, or on a non-default port. # OPENHUMAN_OLLAMA_BASE_URL=http://127.0.0.1:11434 # [optional] Override LM Studio's OpenAI-compatible local server base URL. # Defaults to http://localhost:1234/v1 when local_ai.provider = "lm_studio". OPENHUMAN_LM_STUDIO_BASE_URL= # --------------------------------------------------------------------------- # Local AI binary overrides # --------------------------------------------------------------------------- # [optional] Override path to whisper binary WHISPER_BIN= # [optional] Override path to piper binary PIPER_BIN= # [optional] Override path to ollama binary OLLAMA_BIN= # --------------------------------------------------------------------------- # Telegram managed login # --------------------------------------------------------------------------- # [optional] Bot username for managed Telegram DM linking (default: openhuman_bot) OPENHUMAN_TELEGRAM_BOT_USERNAME=openhuman_bot # [optional] Override Telegram Bot API base URL (defaults to https://api.telegram.org). # Used by E2E tests to redirect Telegram API calls to the mock server. # OPENHUMAN_TELEGRAM_API_BASE=http://127.0.0.1:18473 # --------------------------------------------------------------------------- # Wallet RPC overrides # --------------------------------------------------------------------------- # [optional] Wallet chain RPC URLs. When unset, core falls back to built-in # public mainnet defaults: # EVM -> https://ethereum-rpc.publicnode.com # BTC -> https://blockstream.info/api # Solana -> https://api.mainnet-beta.solana.com # Tron -> https://api.trongrid.io # Override these when you want a private/provisioned RPC, a staging fork, or # a deterministic local chain during tests. # OPENHUMAN_WALLET_RPC_EVM= # OPENHUMAN_WALLET_RPC_BTC= # OPENHUMAN_WALLET_RPC_SOLANA= # OPENHUMAN_WALLET_RPC_TRON= # Solana cluster the wallet broadcasts to: "mainnet" (default) or "devnet". # Selects BOTH the default Solana RPC endpoint and the USDC SPL mint, so a # devnet x402 payment lands on devnet with the devnet mint. Pair with a staging # TINYPLACE_API_BASE_URL when testing tiny.place on devnet. # OPENHUMAN_SOLANA_CLUSTER=devnet # [optional] tiny.place's Solana settlement RPC. ONLY tiny.place payment # broadcasts use this (general wallet ops keep OPENHUMAN_WALLET_RPC_SOLANA): they # try this endpoint first and fall back to the public cluster RPC if it is # unreachable. Defaults to /solana/rpc # (i.e. https://api.tiny.place/solana/rpc), so it tracks prod/staging # automatically — set this only to point settlement at a different RPC. # TINYPLACE_SOLANA_RPC_URL=https://api.tiny.place/solana/rpc # --------------------------------------------------------------------------- # x402 Machine Payments # --------------------------------------------------------------------------- # Budget caps for automatic x402 API payments (atomic USDC: 1 USDC = 1_000_000). # Defaults: per_request=1_000_000 (1 USDC), daily=10_000_000 (10 USDC), # monthly=100_000_000 (100 USDC). # OPENHUMAN_X402_PER_REQUEST_MAX=1000000 # OPENHUMAN_X402_DAILY_MAX=10000000 # OPENHUMAN_X402_MONTHLY_MAX=100000000 # --------------------------------------------------------------------------- # Skills # --------------------------------------------------------------------------- # [optional] Override skills registry URL. # Supports remote HTTP URLs and local file paths for development: # SKILLS_REGISTRY_URL=https://example.com/registry.json (remote) # SKILLS_REGISTRY_URL=/path/to/openhuman-skills/skills/registry.json (local) # When set to a local path, the registry is read directly from disk on every # call (no caching), so changes are picked up immediately. SKILLS_REGISTRY_URL= # [optional] Local skills source directory for development. # Points to the built skills directory (the folder containing per-skill subdirs # with manifest.json + index.js). When set, this takes highest priority for # skill discovery and install will copy from this directory instead of downloading. # Example: SKILLS_LOCAL_DIR=/Users/you/work/openhuman-skills/skills SKILLS_LOCAL_DIR= # [optional] Enable sync-derived user working memory extraction (default: true). # Set to false to disable persisting `working.user.*` docs from skill sync payloads. OPENHUMAN_SKILLS_WORKING_MEMORY_ENABLED=true # --------------------------------------------------------------------------- # Python runtime # --------------------------------------------------------------------------- # [optional] Default: true. Controls whether core may resolve Python for # Python-backed integrations such as stdio MCP servers. # OPENHUMAN_RUNTIME_PYTHON_ENABLED=true # [optional] Minimum acceptable interpreter version (default: 3.12.0). # OPENHUMAN_RUNTIME_PYTHON_MINIMUM_VERSION=3.12.0 # [optional] Pin a specific python-build-standalone release tag. Blank means # query the latest release at install time. # OPENHUMAN_RUNTIME_PYTHON_MANAGED_RELEASE_TAG= # [optional] Reuse a host interpreter before the managed runtime. Default: false. # OPENHUMAN_RUNTIME_PYTHON_PREFER_SYSTEM=false # [optional] Preferred executable name or absolute path. # OPENHUMAN_RUNTIME_PYTHON_PREFERRED_COMMAND=python3.12 # [optional] Reserved cache directory for future managed CPython installs. # OPENHUMAN_RUNTIME_PYTHON_CACHE_DIR= # --------------------------------------------------------------------------- # TokenJuice — content-aware tool-output compaction (the content router) # --------------------------------------------------------------------------- # [optional] Master switch for the content router (default: true). # OPENHUMAN_TOKENJUICE_ENABLED=true # [optional] Offload originals to the CCR cache + emit ⟦tj:…⟧ retrieval markers # (default: true). Disabling makes compaction one-way. # OPENHUMAN_TOKENJUICE_CCR_ENABLED=true # [optional] Persist CCR originals to /.tokenjuice/ccr (default: false). # OPENHUMAN_TOKENJUICE_CCR_DISK_ENABLED=false # [optional] Per-compressor toggles (all default: true). # OPENHUMAN_TOKENJUICE_SEARCH_ENABLED=true # OPENHUMAN_TOKENJUICE_CODE_ENABLED=true # OPENHUMAN_TOKENJUICE_HTML_ENABLED=true # [optional] CCR cache limits. # OPENHUMAN_TOKENJUICE_MAX_CACHE_ENTRIES=256 # OPENHUMAN_TOKENJUICE_MAX_CACHE_BYTES=67108864 # OPENHUMAN_TOKENJUICE_CCR_TTL_SECS= # [optional] CCR only fires (offload + lossy compaction) for results estimated # at >= this many tokens; smaller results pass through. Default 500. # OPENHUMAN_TOKENJUICE_CCR_MIN_TOKENS=500 # [optional] ML plain-text compressor ("Kompress", ModernBERT). Default OFF. # Runs as a `kompress` backend of the shared runtime_python_server (torch is # pip-installed at runtime), so it also requires OPENHUMAN_RUNTIME_PYTHON_ENABLED. # OPENHUMAN_TOKENJUICE_ML_COMPRESSION_ENABLED=false # OPENHUMAN_TOKENJUICE_ML_MODEL_ID=answerdotai/ModernBERT-base # OPENHUMAN_TOKENJUICE_ML_DEVICE=cpu # OPENHUMAN_TOKENJUICE_ML_TARGET_RATIO=0.5 # OPENHUMAN_TOKENJUICE_ML_MAX_INPUT_CHARS=200000 # OPENHUMAN_TOKENJUICE_ML_SIDECAR_IDLE_TIMEOUT_SECS=900 # --------------------------------------------------------------------------- # Error Reporting (Sentry) # --------------------------------------------------------------------------- # [optional] Sentry DSN for Rust core error reporting (no PII is sent). # Reports to the `openhuman-core` Sentry project. The Tauri shell uses a # separate `OPENHUMAN_TAURI_SENTRY_DSN`; the React frontend uses # `VITE_SENTRY_DSN`. The legacy unprefixed name `OPENHUMAN_SENTRY_DSN` is # still accepted as a fallback during the transition. OPENHUMAN_CORE_SENTRY_DSN= # [optional] Override the Sentry server URL. Defaults to sentry.io if unset. # Set to https://sentry.tinyhumans.ai for the self-hosted instance — used by # sentry-cli (symbol/release uploads) and the @sentry/vite-plugin. SENTRY_URL= # [optional] Short git SHA baked into the Sentry release tag # (`openhuman@+`) via `option_env!("OPENHUMAN_BUILD_SHA")`. # CI sets this automatically; leave blank locally (release tag falls back # to `openhuman@`). OPENHUMAN_BUILD_SHA= # [optional] Default: true — set to false to disable anonymized analytics & crash reports OPENHUMAN_ANALYTICS_ENABLED=true # --------------------------------------------------------------------------- # Composio memory-sync (per-provider knobs) # --------------------------------------------------------------------------- # All values below are [optional] runtime overrides for memory-sync providers # (gmail / slack / notion / clickup / github / linear). Compile-time defaults # match what shipped before these vars existed; only set what you need to # change. # # Daily request budget per (toolkit, connection) pair. Compile-time default is # 500 — enough for steady-state but easy to exhaust mid-backfill on chatty # workspaces. Raise to widen the cap; non-positive / non-numeric values fall # back to 500 with a `warn`. # OPENHUMAN_COMPOSIO_DAILY_REQUEST_LIMIT=2000 # # Per-toolkit periodic sync cadence (seconds). Compile-time defaults: gmail / # slack = 900 (15m), notion / clickup / github / linear = 1800 (30m). Raise # the interval to burn the daily budget more slowly. Non-positive / non- # numeric values fall back to the compile-time default with a `warn`. # OPENHUMAN_COMPOSIO_GMAIL_SYNC_INTERVAL_SECS=1800 # OPENHUMAN_COMPOSIO_SLACK_SYNC_INTERVAL_SECS=3600 # OPENHUMAN_COMPOSIO_NOTION_SYNC_INTERVAL_SECS=3600 # OPENHUMAN_COMPOSIO_CLICKUP_SYNC_INTERVAL_SECS=3600 # OPENHUMAN_COMPOSIO_GITHUB_SYNC_INTERVAL_SECS=3600 # OPENHUMAN_COMPOSIO_LINEAR_SYNC_INTERVAL_SECS=3600 # # Global memory-sync cadence (seconds) applied to ALL opted-in sources, # overriding the per-provider defaults above (floored at each provider default # so we never sync more often than the provider intends). This is the ops-level # equivalent of the Memory Sources schedule control (#3302). Normally set from # the UI; this var is for headless / fleet deployments. `0` means "Manual only" # (periodic auto-sync disabled). Unset → 24h default. # OPENHUMAN_MEMORY_SYNC_INTERVAL_SECS=86400 # --------------------------------------------------------------------------- # Logging # --------------------------------------------------------------------------- # [optional] Default: info RUST_LOG=info # [optional] Default: 0 (set to 1 for full backtraces) RUST_BACKTRACE=1 # --------------------------------------------------------------------------- # tiny.place Agent World integration # --------------------------------------------------------------------------- # [optional] Base URL for the tiny.place backend API. # When unset, the default follows OPENHUMAN_APP_ENV: a `staging` app env uses # https://staging-api.tiny.place, otherwise https://api.tiny.place (production). # Set this to pin an explicit host — it always overrides the app-env default. # TINYPLACE_API_BASE_URL=https://staging-api.tiny.place # --------------------------------------------------------------------------- # Testing (do not set in production) # --------------------------------------------------------------------------- # [optional] Disable the cross-agent file-state guard (staleness detection # for parallel subagent writes). Set to 0/false/off/no to disable. # OPENHUMAN_FILE_STATE_GUARD=1 # [optional] Enable mock service mode # OPENHUMAN_SERVICE_MOCK=0 # [optional] Path to mock state file # OPENHUMAN_SERVICE_MOCK_STATE_FILE= # --------------------------------------------------------------------------- # AgentBox marketplace (GMI Cloud) — opt-in container surface. # Set OPENHUMAN_AGENTBOX_MODE=1 to expose POST /run and GET /jobs/{job_id}. # The remaining GMI_MAAS_* and GMI_MODELS variables are injected by the # AgentBox console at deploy time; for local testing of the /run path set # them yourself (they MUST be non-blank). # --------------------------------------------------------------------------- # OPENHUMAN_AGENTBOX_MODE=0 # OPENHUMAN_AGENTBOX_JOB_TIMEOUT_SECS=600 # GMI_MAAS_BASE_URL=https://api.gmi-serving.com # GMI_MAAS_API_KEY= # GMI_MODELS=deepseek-ai/DeepSeek-V4-Pro