File size: 2,528 Bytes
5871090
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
export type Profile = "cloud" | "local";

function readProfile(): Profile {
  const raw = (process.env["DOATLAS_PROFILE"] || "cloud").toLowerCase();
  return raw === "local" ? "local" : "cloud";
}

const env = process.env;

// Replit-managed AI integrations (cloud-billed).
const hasAnthropicCloud = Boolean(env["AI_INTEGRATIONS_ANTHROPIC_BASE_URL"]);
const hasOpenAICloud = Boolean(env["AI_INTEGRATIONS_OPENAI_BASE_URL"]);
const hasGeminiCloud = Boolean(env["AI_INTEGRATIONS_GEMINI_BASE_URL"]);

// User-supplied direct keys (local deployment / private hosting).
const hasAnthropicDirect = Boolean(env["ANTHROPIC_API_KEY"]);
const hasOpenAIDirect = Boolean(env["OPENAI_API_KEY"]);
const hasGeminiDirect = Boolean(env["GEMINI_API_KEY"]);

export const config = {
  profile: readProfile(),
  appVersion: env["DOATLAS_VERSION"] || "1.0.0",
  buildSha: env["DOATLAS_BUILD"] || "dev",
  // In dev, allow ergonomic invite codes when none are configured.
  inviteCodes: (
    env["INVITE_CODES"] ||
    (env["NODE_ENV"] !== "production"
      ? "INVITE-DEMO,INVITE-DOATLAS,INVITE-TEST"
      : "")
  )
    .split(",")
    .map((c) => c.trim())
    .filter(Boolean),

  // -- Cloud (Replit-managed) availability --
  hasAnthropicCloud,
  hasOpenAICloud,
  hasGeminiCloud,

  // -- Direct provider availability (works in both profiles) --
  hasAnthropicDirect,
  hasOpenAIDirect,
  hasGeminiDirect,

  // -- Aggregated availability (any source counts) --
  hasAnthropic: hasAnthropicCloud || hasAnthropicDirect,
  hasOpenAI: hasOpenAICloud || hasOpenAIDirect,
  hasGemini: hasGeminiCloud || hasGeminiDirect,

  // -- Local-only providers (require direct API key) --
  hasDeepseek: Boolean(env["DEEPSEEK_API_KEY"]),
  hasKimi: Boolean(env["MOONSHOT_API_KEY"] || env["KIMI_API_KEY"]),
  hasZhipu: Boolean(env["ZHIPU_API_KEY"]),
  hasMinimax: Boolean(env["MINIMAX_API_KEY"]),
  hasQwen: Boolean(env["DASHSCOPE_API_KEY"] || env["QWEN_API_KEY"]),
  hasCodexCli: Boolean(env["CODEX_CLI_BIN"]),
};

export function featureFlags(): Record<string, boolean> {
  const llmAvailable =
    config.profile === "cloud"
      ? config.hasAnthropic || config.hasOpenAI || config.hasGemini
      : config.hasAnthropic ||
        config.hasOpenAI ||
        config.hasGemini ||
        config.hasDeepseek ||
        config.hasKimi ||
        config.hasZhipu ||
        config.hasMinimax ||
        config.hasQwen ||
        config.hasCodexCli;
  return {
    streaming: llmAvailable,
    voice: false,
    attachments: false,
    artifacts: false,
  };
}