import type { SecretInput } from "./types.secrets.js"; export type GatewayBindMode = "auto" | "lan" | "loopback" | "custom" | "tailnet"; export type GatewayTlsConfig = { /** Enable TLS for the gateway server. */ enabled?: boolean; /** Auto-generate a self-signed cert if cert/key are missing (default: true). */ autoGenerate?: boolean; /** PEM certificate path for the gateway server. */ certPath?: string; /** PEM private key path for the gateway server. */ keyPath?: string; /** Optional PEM CA bundle for TLS clients (mTLS or custom roots). */ caPath?: string; }; export type WideAreaDiscoveryConfig = { enabled?: boolean; /** Optional unicast DNS-SD domain (e.g. "openclaw.internal"). */ domain?: string; }; export type MdnsDiscoveryMode = "off" | "minimal" | "full"; export type MdnsDiscoveryConfig = { /** * mDNS/Bonjour discovery broadcast mode (default: minimal). * - off: disable mDNS entirely * - minimal: omit cliPath/sshPort from TXT records * - full: include cliPath/sshPort in TXT records */ mode?: MdnsDiscoveryMode; }; export type DiscoveryConfig = { wideArea?: WideAreaDiscoveryConfig; mdns?: MdnsDiscoveryConfig; }; export type CanvasHostConfig = { enabled?: boolean; /** Directory to serve (default: ~/.openclaw/workspace/canvas). */ root?: string; /** HTTP port to listen on (default: 18793). */ port?: number; /** Enable live-reload file watching + WS reloads (default: true). */ liveReload?: boolean; }; export type TalkProviderConfig = { /** Provider API key (optional; provider-specific env fallback may apply). */ apiKey?: SecretInput; /** Provider-owned Talk config fields. */ [key: string]: unknown; }; export type ResolvedTalkConfig = { /** Active Talk TTS provider resolved from the current config payload. */ provider: string; /** Provider config for the active Talk provider. */ config: TalkProviderConfig; }; export type TalkConfig = { /** Active Talk TTS provider (for example "acme-speech"). */ provider?: string; /** Provider-specific Talk config keyed by provider id. */ providers?: Record; /** BCP 47 locale id used for Talk speech recognition on device nodes. */ speechLocale?: string; /** Stop speaking when user starts talking (default: true). */ interruptOnSpeech?: boolean; /** Milliseconds of user silence before Talk mode sends the transcript after a pause. */ silenceTimeoutMs?: number; }; export type TalkConfigResponse = TalkConfig & { /** Canonical active Talk payload for clients. */ resolved?: ResolvedTalkConfig; }; export type GatewayControlUiConfig = { /** If false, the Gateway will not serve the Control UI (default /). */ enabled?: boolean; /** Optional base path prefix for the Control UI (e.g. "/openclaw"). */ basePath?: string; /** Optional filesystem root for Control UI assets (defaults to dist/control-ui). */ root?: string; /** * Embed sandbox mode for hosted Control UI previews. * - strict: no script execution inside embeds * - scripts: allow scripts while keeping embeds origin-isolated (default) * - trusted: allow scripts and same-origin privileges */ embedSandbox?: "strict" | "scripts" | "trusted"; /** * DANGEROUS: Allow hosted embeds to load absolute external http(s) URLs. * Default off; prefer hosted /__openclaw__/canvas or /__openclaw__/a2ui content. */ allowExternalEmbedUrls?: boolean; /** Optional max-width for grouped Control UI chat messages (default: min(900px, 68%)). */ chatMessageMaxWidth?: string; /** Allowed browser origins for Control UI/WebChat websocket connections. */ allowedOrigins?: string[]; /** * DANGEROUS: Keep Host-header origin fallback behavior. * Supported long-term for deployments that intentionally rely on this policy. */ dangerouslyAllowHostHeaderOriginFallback?: boolean; /** * Insecure-auth toggle. * Control UI still requires secure context + device identity unless * dangerouslyDisableDeviceAuth is enabled. */ allowInsecureAuth?: boolean; /** DANGEROUS: Disable device identity checks for the Control UI (default: false). */ dangerouslyDisableDeviceAuth?: boolean; }; export type GatewayAuthMode = "none" | "token" | "password" | "trusted-proxy"; /** * Configuration for trusted reverse proxy authentication. * Used when Clawdbot runs behind an identity-aware proxy (Pomerium, Caddy + OAuth, etc.) * that handles authentication and passes user identity via headers. */ export type GatewayTrustedProxyConfig = { /** * Header name containing the authenticated user identity (required). * Common values: "x-forwarded-user", "x-remote-user", "x-pomerium-claim-email" */ userHeader: string; /** * Additional headers that MUST be present for the request to be trusted. * Use this to verify the request actually came through the proxy. * Example: ["x-forwarded-proto", "x-forwarded-host"] */ requiredHeaders?: string[]; /** * Optional allowlist of user identities that can access the gateway. * If empty or omitted, all authenticated users from the proxy are allowed. * Example: ["nick@example.com", "admin@company.org"] */ allowUsers?: string[]; /** * Allow loopback proxy sources (127.0.0.1, ::1) in trusted-proxy mode. * Default false; enable only when a same-host reverse proxy is the intended * trust boundary and direct Gateway access is otherwise locked down. */ allowLoopback?: boolean; }; export type GatewayAuthConfig = { /** Authentication mode for Gateway connections. Defaults to token when unset. */ mode?: GatewayAuthMode; /** Shared token for token mode (plaintext or SecretRef). */ token?: SecretInput; /** Shared password for password mode (consider env instead). */ password?: SecretInput; /** Allow Tailscale identity headers when serve mode is enabled. */ allowTailscale?: boolean; /** Rate-limit configuration for failed authentication attempts. */ rateLimit?: GatewayAuthRateLimitConfig; /** * Configuration for trusted-proxy auth mode. * Required when mode is "trusted-proxy". */ trustedProxy?: GatewayTrustedProxyConfig; }; export type GatewayAuthRateLimitConfig = { /** Maximum failed attempts per IP before blocking. @default 10 */ maxAttempts?: number; /** Sliding window duration in milliseconds. @default 60000 (1 min) */ windowMs?: number; /** Lockout duration in milliseconds after the limit is exceeded. @default 300000 (5 min) */ lockoutMs?: number; /** Exempt localhost/loopback addresses from auth rate limiting. @default true */ exemptLoopback?: boolean; }; export type GatewayTailscaleMode = "off" | "serve" | "funnel"; export type GatewayTailscaleConfig = { /** Tailscale exposure mode for the Gateway control UI. */ mode?: GatewayTailscaleMode; /** Reset serve/funnel configuration on shutdown. */ resetOnExit?: boolean; }; export type GatewayRemoteConfig = { /** Whether remote gateway surfaces are enabled. Default: true when absent. */ enabled?: boolean; /** Remote Gateway WebSocket URL (ws:// or wss://). */ url?: string; /** Transport for macOS remote connections (ssh tunnel or direct WS). */ transport?: "ssh" | "direct"; /** Token for remote auth (when the gateway requires token auth). */ token?: SecretInput; /** Password for remote auth (when the gateway requires password auth). */ password?: SecretInput; /** Expected TLS certificate fingerprint (sha256) for remote gateways. */ tlsFingerprint?: string; /** SSH target for tunneling remote Gateway (user@host). */ sshTarget?: string; /** SSH identity file path for tunneling remote Gateway. */ sshIdentity?: string; }; export type GatewayReloadMode = "off" | "restart" | "hot" | "hybrid"; export type GatewayReloadConfig = { /** Reload strategy for config changes (default: hybrid). */ mode?: GatewayReloadMode; /** Debounce window for config reloads (ms). Default: 300. */ debounceMs?: number; /** * Optional maximum time (ms) to wait for in-flight operations to complete * before forcing a restart. Absent uses the gateway's default bounded wait; * 0 waits indefinitely and logs periodic still-pending warnings. * Lower positive values risk aborting active subagent LLM calls. * @see https://github.com/openclaw/openclaw/issues/65485 */ deferralTimeoutMs?: number; }; export type GatewayHttpChatCompletionsConfig = { /** * If false, the Gateway will not serve `POST /v1/chat/completions`. * Default: false when absent. */ enabled?: boolean; /** * Max request body size in bytes for `/v1/chat/completions`. * Default: 20MB. */ maxBodyBytes?: number; /** * Max number of `image_url` parts processed from the latest user message. * Default: 8. */ maxImageParts?: number; /** * Max cumulative decoded image bytes for all `image_url` parts in one request. * Default: 20MB. */ maxTotalImageBytes?: number; /** Image input controls for `image_url` parts. */ images?: GatewayHttpChatCompletionsImagesConfig; }; export type GatewayHttpChatCompletionsImagesConfig = { /** Allow URL fetches for `image_url` parts. Default: false. */ allowUrl?: boolean; /** * Optional hostname allowlist for URL fetches. * Supports exact hosts and `*.example.com` wildcards. */ urlAllowlist?: string[]; /** Allowed MIME types (case-insensitive). */ allowedMimes?: string[]; /** Max bytes per image. Default: 10MB. */ maxBytes?: number; /** Max redirects when fetching a URL. Default: 3. */ maxRedirects?: number; /** Fetch timeout in ms. Default: 10s. */ timeoutMs?: number; }; export type GatewayHttpResponsesConfig = { /** * If false, the Gateway will not serve `POST /v1/responses` (OpenResponses API). * Default: false when absent. */ enabled?: boolean; /** * Max request body size in bytes for `/v1/responses`. * Default: 20MB. */ maxBodyBytes?: number; /** * Max number of URL-based `input_file` + `input_image` parts per request. * Default: 8. */ maxUrlParts?: number; /** File inputs (input_file). */ files?: GatewayHttpResponsesFilesConfig; /** Image inputs (input_image). */ images?: GatewayHttpResponsesImagesConfig; }; export type GatewayHttpResponsesFilesConfig = { /** Allow URL fetches for input_file. Default: true. */ allowUrl?: boolean; /** * Optional hostname allowlist for URL fetches. * Supports exact hosts and `*.example.com` wildcards. */ urlAllowlist?: string[]; /** Allowed MIME types (case-insensitive). */ allowedMimes?: string[]; /** Max bytes per file. Default: 5MB. */ maxBytes?: number; /** Max decoded characters per file. Default: 200k. */ maxChars?: number; /** Max redirects when fetching a URL. Default: 3. */ maxRedirects?: number; /** Fetch timeout in ms. Default: 10s. */ timeoutMs?: number; /** PDF handling (application/pdf). */ pdf?: GatewayHttpResponsesPdfConfig; }; export type GatewayHttpResponsesPdfConfig = { /** Max pages to parse/render. Default: 4. */ maxPages?: number; /** Max pixels per rendered page. Default: 4M. */ maxPixels?: number; /** Minimum extracted text length to skip rasterization. Default: 200 chars. */ minTextChars?: number; }; export type GatewayHttpResponsesImagesConfig = { /** Allow URL fetches for input_image. Default: true. */ allowUrl?: boolean; /** * Optional hostname allowlist for URL fetches. * Supports exact hosts and `*.example.com` wildcards. */ urlAllowlist?: string[]; /** Allowed MIME types (case-insensitive). */ allowedMimes?: string[]; /** Max bytes per image. Default: 10MB. */ maxBytes?: number; /** Max redirects when fetching a URL. Default: 3. */ maxRedirects?: number; /** Fetch timeout in ms. Default: 10s. */ timeoutMs?: number; }; export type GatewayHttpEndpointsConfig = { chatCompletions?: GatewayHttpChatCompletionsConfig; responses?: GatewayHttpResponsesConfig; }; export type GatewayHttpSecurityHeadersConfig = { /** * Value for the Strict-Transport-Security response header. * Set to false to disable explicitly. * * Example: "max-age=31536000; includeSubDomains" */ strictTransportSecurity?: string | false; }; export type GatewayHttpConfig = { endpoints?: GatewayHttpEndpointsConfig; securityHeaders?: GatewayHttpSecurityHeadersConfig; }; export type GatewayPushApnsRelayConfig = { /** Base HTTPS URL for the external iOS APNs relay service. */ baseUrl?: string; /** Timeout in milliseconds for relay send requests (default: 10000). */ timeoutMs?: number; }; export type GatewayPushApnsConfig = { relay?: GatewayPushApnsRelayConfig; }; export type GatewayPushConfig = { apns?: GatewayPushApnsConfig; }; export type GatewayNodePairingConfig = { /** * Opt-in CIDR/IP allowlist for auto-approving first-time node-role pairing. * Only applies to fresh node pairing requests with no requested scopes. * Default: unset/disabled. */ autoApproveCidrs?: string[]; }; export type GatewayNodesConfig = { /** Browser routing policy for node-hosted browser proxies. */ browser?: { /** Routing mode (default: auto). */ mode?: "auto" | "manual" | "off"; /** Pin to a specific node id/name (optional). */ node?: string; }; /** Pairing policy for node-role gateway clients. */ pairing?: GatewayNodePairingConfig; /** Additional node.invoke commands to allow on the gateway. */ allowCommands?: string[]; /** Commands to deny even if they appear in the defaults or node claims. */ denyCommands?: string[]; }; export type GatewayToolsConfig = { /** Tools to deny via gateway HTTP /tools/invoke (extends defaults). */ deny?: string[]; /** Tools to explicitly allow (removes from default deny list). */ allow?: string[]; }; export type GatewayWebchatConfig = { /** Max characters per text field in chat.history responses before truncation (default: 12000). */ chatHistoryMaxChars?: number; }; export type GatewayConfig = { /** Single multiplexed port for Gateway WS + HTTP (default: 18789). */ port?: number; /** * Explicit gateway mode. When set to "remote", local gateway start is disabled. * When set to "local", the CLI may start the gateway locally. */ mode?: "local" | "remote"; /** * Bind address policy for the Gateway WebSocket + Control UI HTTP server. * - auto: Loopback (127.0.0.1) if available, else 0.0.0.0 (fallback to all interfaces) * - lan: 0.0.0.0 (all interfaces, no fallback) * - loopback: 127.0.0.1 (local-only) * - tailnet: Tailnet IPv4 if available (100.64.0.0/10), else loopback * - custom: User-specified IP, fallback to 0.0.0.0 if unavailable (requires customBindHost) * Default: loopback (127.0.0.1). */ bind?: GatewayBindMode; /** Custom IP address for bind="custom" mode. Fallback: 0.0.0.0. */ customBindHost?: string; controlUi?: GatewayControlUiConfig; auth?: GatewayAuthConfig; tailscale?: GatewayTailscaleConfig; remote?: GatewayRemoteConfig; reload?: GatewayReloadConfig; tls?: GatewayTlsConfig; http?: GatewayHttpConfig; push?: GatewayPushConfig; nodes?: GatewayNodesConfig; /** * IPs of trusted reverse proxies (e.g. Traefik, nginx). When a connection * arrives from one of these IPs, the Gateway trusts `x-forwarded-for` * to determine the client IP for local pairing and HTTP checks. */ trustedProxies?: string[]; /** * Allow `x-real-ip` as a fallback only when `x-forwarded-for` is missing. * Default: false (safer fail-closed behavior). */ allowRealIpFallback?: boolean; /** Tool access restrictions for HTTP /tools/invoke endpoint. */ tools?: GatewayToolsConfig; /** WebChat display/history settings. */ webchat?: GatewayWebchatConfig; /** * Pre-auth Gateway WebSocket handshake timeout in milliseconds. * Env var OPENCLAW_HANDSHAKE_TIMEOUT_MS takes precedence. Default: 15000. */ handshakeTimeoutMs?: number; /** * Channel health monitor interval in minutes. * Periodically checks channel health and restarts unhealthy channels. * Set to 0 to disable. Default: 5. */ channelHealthCheckMinutes?: number; /** * Stale transport-activity threshold in minutes for the channel health monitor. * A connected channel that reports no provider-proven transport activity for * this duration is treated as a stale socket and restarted. Default: 30. */ channelStaleEventThresholdMinutes?: number; /** * Maximum number of health-monitor-initiated channel restarts per hour. * Once this limit is reached, the monitor skips further restarts until * the rolling window expires. Default: 10. */ channelMaxRestartsPerHour?: number; };