| export const DEFAULT_WORKING_DIR = "workspace/project"; |
|
|
| export type LockedCloudAuthMode = "api-key" | "cookie"; |
|
|
| export interface AgentServerFormDefaults { |
| baseUrl: string; |
| sessionApiKey: string; |
| } |
|
|
| |
| |
| |
| |
| const LOCK_TO_CLOUD_WINDOW_KEY = "__AGENT_CANVAS_LOCK_TO_CLOUD__"; |
| const LEGACY_CLOUD_DOMAIN = "all-hands.dev"; |
| const CURRENT_CLOUD_DOMAIN = "openhands.dev"; |
| const LEGACY_PRODUCTION_APP_HOST = `app.${LEGACY_CLOUD_DOMAIN}`; |
| const CURRENT_PRODUCTION_APP_HOST = CURRENT_CLOUD_DOMAIN; |
| const PRODUCTION_APP_HOST_ALIAS = `app.${CURRENT_CLOUD_DOMAIN}`; |
|
|
| function trimToNull(value?: string | null): string | null { |
| return value?.trim() || null; |
| } |
|
|
| function normalizeBaseUrl(value?: string | null): string | null { |
| if (!value) return null; |
|
|
| const trimmed = value.trim().replace(/\/$/, ""); |
| if (!trimmed) return null; |
|
|
| if (/^https?:\/\//i.test(trimmed)) { |
| return trimmed; |
| } |
|
|
| if (typeof window !== "undefined") { |
| return `${window.location.protocol}//${trimmed}`; |
| } |
|
|
| return `http://${trimmed}`; |
| } |
|
|
| function normalizeCloudHost(value?: string | null): string | null { |
| if (!value) return null; |
|
|
| const trimmed = value.trim().replace(/\/+$/, ""); |
| if (!trimmed) return null; |
|
|
| if (/^https?:\/\//i.test(trimmed)) { |
| return trimmed; |
| } |
|
|
| return `https://${trimmed}`; |
| } |
|
|
| function canonicalizeCloudHostname(hostname: string): string { |
| const lower = hostname.toLowerCase(); |
| if ( |
| lower === LEGACY_PRODUCTION_APP_HOST || |
| lower === PRODUCTION_APP_HOST_ALIAS |
| ) { |
| return CURRENT_PRODUCTION_APP_HOST; |
| } |
|
|
| if (lower === LEGACY_CLOUD_DOMAIN) return CURRENT_CLOUD_DOMAIN; |
| if (lower.endsWith(`.${LEGACY_CLOUD_DOMAIN}`)) { |
| return `${lower.slice(0, -LEGACY_CLOUD_DOMAIN.length)}${CURRENT_CLOUD_DOMAIN}`; |
| } |
|
|
| return lower; |
| } |
|
|
| function getCloudHostComparisonKey(value?: string | null): string | null { |
| const normalized = normalizeCloudHost(value); |
| if (!normalized) return null; |
|
|
| try { |
| const url = new URL(normalized); |
| const port = url.port ? `:${url.port}` : ""; |
| return `${url.protocol}//${canonicalizeCloudHostname(url.hostname)}${port}`; |
| } catch { |
| return normalized.toLowerCase(); |
| } |
| } |
|
|
| export function getCookieAuthCloudHost(): string | null { |
| const lockedHost = getLockedCloudHost(); |
| if ( |
| !lockedHost || |
| typeof window === "undefined" || |
| !isSameCloudHost(window.location.origin, lockedHost) |
| ) { |
| return null; |
| } |
|
|
| return window.location.origin; |
| } |
|
|
| function getConfiguredBaseUrl(): string | null { |
| return normalizeBaseUrl(import.meta.env.VITE_BACKEND_BASE_URL); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function getBakedSessionApiKey(): string | null { |
| const envKey = trimToNull(import.meta.env.VITE_SESSION_API_KEY); |
| if (envKey) return envKey; |
|
|
| if (typeof window !== "undefined") { |
| const injected = (window as unknown as Record<string, unknown>) |
| .__AGENT_CANVAS_SESSION_API_KEY__; |
| if (typeof injected === "string") { |
| return trimToNull(injected); |
| } |
| } |
|
|
| return null; |
| } |
|
|
| export function getAgentServerFormDefaults(): AgentServerFormDefaults { |
| return { |
| baseUrl: getAgentServerBaseUrl() ?? "", |
| sessionApiKey: getAgentServerSessionApiKey() ?? "", |
| }; |
| } |
|
|
| export function getLockedCloudHost(): string | null { |
| const envHost = normalizeCloudHost(import.meta.env.VITE_LOCK_TO_CLOUD); |
| if (envHost) return envHost; |
|
|
| if (typeof window !== "undefined") { |
| const injected = (window as unknown as Record<string, unknown>)[ |
| LOCK_TO_CLOUD_WINDOW_KEY |
| ]; |
| if (typeof injected === "string") { |
| return normalizeCloudHost(injected); |
| } |
| } |
|
|
| return null; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function isSameCloudHost( |
| host: string | null | undefined, |
| lockedHost: string | null | undefined, |
| ): boolean { |
| const a = getCloudHostComparisonKey(host); |
| const b = getCloudHostComparisonKey(lockedHost); |
| if (!a || !b) return false; |
| return a === b; |
| } |
|
|
| export function getLockedCloudAuthMode(): LockedCloudAuthMode { |
| return getCookieAuthCloudHost() ? "cookie" : "api-key"; |
| } |
|
|
| export function getAgentServerBaseUrl(): string | null { |
| const configuredUrl = getConfiguredBaseUrl(); |
| if (configuredUrl) return configuredUrl; |
|
|
| if (typeof window !== "undefined") { |
| return window.location.origin; |
| } |
|
|
| return null; |
| } |
|
|
| export function getAgentServerSessionApiKey(): string | null { |
| return getBakedSessionApiKey(); |
| } |
|
|
| export function getAgentServerWorkingDir(): string { |
| const envDir = import.meta.env.VITE_WORKING_DIR?.trim(); |
| if (envDir) return envDir; |
|
|
| return DEFAULT_WORKING_DIR; |
| } |
|
|
| function buildWorkingDir(base: string, conversationId: string): string { |
| const trimmed = base.replace(/\/+$/, ""); |
| const hex = conversationId.replace(/-/g, ""); |
| return `${trimmed}/${hex}`; |
| } |
|
|
| export function buildConversationWorkingDir(conversationId: string): string { |
| return buildWorkingDir(getAgentServerWorkingDir(), conversationId); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| export function buildRelativeConversationWorkingDir( |
| conversationId: string, |
| ): string { |
| return buildWorkingDir(DEFAULT_WORKING_DIR, conversationId); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function isServedOriginHost( |
| backendHost: string | null | undefined, |
| ): boolean { |
| const served = normalizeBaseUrl(getAgentServerBaseUrl()); |
| const candidate = normalizeBaseUrl(backendHost); |
| if (!served || !candidate) return false; |
| return served === candidate; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function buildConversationWorkingDirForBackend( |
| conversationId: string, |
| backendHost: string | null | undefined, |
| ): string { |
| return isServedOriginHost(backendHost) |
| ? buildConversationWorkingDir(conversationId) |
| : buildRelativeConversationWorkingDir(conversationId); |
| } |
|
|
| |
| |
| |
| |
| |
| export function getWorkspaceRootForBackend( |
| backendHost: string | null | undefined, |
| ): string { |
| return isServedOriginHost(backendHost) |
| ? getAgentServerWorkingDir() |
| : DEFAULT_WORKING_DIR; |
| } |
|
|
| export function getAgentServerHeaders(): Record<string, string> { |
| const sessionApiKey = getAgentServerSessionApiKey(); |
| return sessionApiKey ? { "X-Session-API-Key": sessionApiKey } : {}; |
| } |
|
|
| export function isAuthRequired(): boolean { |
| return ( |
| import.meta.env.VITE_AUTH_REQUIRED === "true" || |
| (typeof window !== "undefined" && |
| (window as unknown as Record<string, unknown>) |
| .__AGENT_CANVAS_AUTH_REQUIRED__ === true) |
| ); |
| } |
|
|
| export function isAuthRequiredAndMissing(): boolean { |
| if (!isAuthRequired()) return false; |
| return !getAgentServerSessionApiKey(); |
| } |
|
|