From f613821bfb3808b2765642f5dbd441878802a237 Mon Sep 17 00:00:00 2001 From: Release Repro Date: Fri, 31 Jul 2026 13:10:08 -0400 Subject: [PATCH] feat(llm): add direct DeepSeek provider --- .env.example | 1 + .../public/images/providers/deepseek.svg | 3 + .../administration/server-configuration.mdx | 1 + docs/public/core-concepts/models.mdx | 4 +- docs/public/docs.json | 1 + docs/public/integrations/deepseek.mdx | 109 ++++++++++++++++++ docs/public/reference/sdk.mdx | 1 + lib/apps/fabro-cli/src/commands/install.rs | 1 + .../fabro-llm/src/adapter_registry.rs | 2 + .../src/codec/openai_compatible/wire.rs | 22 ++++ lib/components/fabro-llm/tests/integration.rs | 22 ++++ lib/foundation/fabro-model/src/catalog.rs | 99 +++++++++++++++- .../src/catalog/providers/deepseek.toml | 61 ++++++++++ lib/foundation/fabro-static/src/env_vars.rs | 2 + .../fabro-static/src/secret_registry.rs | 2 + 15 files changed, 329 insertions(+), 2 deletions(-) create mode 100644 apps/fabro-web/public/images/providers/deepseek.svg create mode 100644 docs/public/integrations/deepseek.mdx create mode 100644 lib/foundation/fabro-model/src/catalog/providers/deepseek.toml diff --git a/.env.example b/.env.example index ea69ab76b..c9f059ea1 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,7 @@ ANTHROPIC_API_KEY= BRAVE_SEARCH_API_KEY= DAYTONA_API_KEY= +DEEPSEEK_API_KEY= FIREWORKS_API_KEY= GEMINI_API_KEY= INCEPTION_API_KEY= diff --git a/apps/fabro-web/public/images/providers/deepseek.svg b/apps/fabro-web/public/images/providers/deepseek.svg new file mode 100644 index 000000000..5d6efa991 --- /dev/null +++ b/apps/fabro-web/public/images/providers/deepseek.svg @@ -0,0 +1,3 @@ + + + diff --git a/docs/public/administration/server-configuration.mdx b/docs/public/administration/server-configuration.mdx index c806406f7..9f107d046 100644 --- a/docs/public/administration/server-configuration.mdx +++ b/docs/public/administration/server-configuration.mdx @@ -388,6 +388,7 @@ fabro secret set GEMINI_API_KEY AI... | `MINIMAX_API_KEY` | Minimax | | `INCEPTION_API_KEY` | Inception (Mercury) | | `POOLSIDE_API_KEY` | Poolside (Laguna) | +| `DEEPSEEK_API_KEY` | DeepSeek | | `OPENROUTER_API_KEY` | OpenRouter (when enabled) | | `MODAL_TOKEN_ID` and `MODAL_TOKEN_SECRET` | Modal (when enabled) | | `FIREWORKS_API_KEY` | Fireworks AI (when enabled) | diff --git a/docs/public/core-concepts/models.mdx b/docs/public/core-concepts/models.mdx index a4befa37f..84f00bb1e 100644 --- a/docs/public/core-concepts/models.mdx +++ b/docs/public/core-concepts/models.mdx @@ -59,13 +59,15 @@ Fabro performs this selection once when creating a run and persists the chosen p | `gemini-3.1-flash-lite` | gemini | `gemini-flash-lite`, `gemini-3.1-flash-lite-preview` | 1M | $0.25 / $1.50 | 200 tok/s | | `kimi-k2.5` | kimi | | 262K | $0.60 / $3.00 | 50 tok/s | | `kimi-k3` | kimi | `kimi` | 1M | $3.00 / $15.00 | n/a | +| `deepseek-v4-flash` | deepseek | `deepseek`, `deepseek-v4`, `deepseek-flash` | 1,048,576 | $0.14 / $0.28 | n/a | +| `deepseek-v4-pro` | deepseek | | 1,048,576 | $0.435 / $0.87 | n/a | | `laguna-s-2.1` | poolside | `laguna`, `laguna-s` | 1M | $0.10 / $0.20 | n/a | | `laguna-xs-2.1` | poolside | `laguna-xs` | 262K | $0.10 / $0.20 | n/a | | `glm-5.2` | zai | `glm`, `glm5`, `glm52`, `glm5.2` | 1M | $1.40 / $4.40 | n/a | | `minimax-m2.5` | minimax | `minimax` | 197K | $0.30 / $1.20 | 45 tok/s | | `mercury-2` | inception | `mercury` | 131K | $0.25 / $0.75 | 1000 tok/s | -Each provider requires its own API key. Server-backed workflows read provider credentials from the server vault (for example `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, or `POOLSIDE_API_KEY` set with `fabro secret set` or `fabro provider login`). Standalone SDK/CLI flows can opt into env-backed credential sources explicitly. See the [Quick Start](/getting-started/quick-start) for setup. +Each provider requires its own API key. Server-backed workflows read provider credentials from the server vault (for example `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `DEEPSEEK_API_KEY`, or `POOLSIDE_API_KEY` set with `fabro secret set` or `fabro provider login`). Standalone SDK/CLI flows can opt into env-backed credential sources explicitly. See the [Quick Start](/getting-started/quick-start) for setup. Claude Fable 5 is available as an explicit model but is not the default Anthropic model. If Fable refuses a request, Fabro reports the refusal as a content-filter LLM error and applies the configured `run.model.fallbacks` chain when one is present. diff --git a/docs/public/docs.json b/docs/public/docs.json index e00f0d711..faf0d0f84 100644 --- a/docs/public/docs.json +++ b/docs/public/docs.json @@ -96,6 +96,7 @@ "integrations/daytona", "integrations/litellm", "integrations/bedrock", + "integrations/deepseek", "integrations/poolside", "integrations/openrouter", "integrations/modal", diff --git a/docs/public/integrations/deepseek.mdx b/docs/public/integrations/deepseek.mdx new file mode 100644 index 000000000..9180a0461 --- /dev/null +++ b/docs/public/integrations/deepseek.mdx @@ -0,0 +1,109 @@ +--- +title: "DeepSeek" +description: "Run DeepSeek V4 Flash and Pro through DeepSeek's direct API or supported gateways" +--- + +[DeepSeek](https://www.deepseek.com/) provides an OpenAI-compatible API for DeepSeek V4. Fabro includes direct access to V4 Flash and V4 Pro. The same Fabro model IDs also work through the optional Fireworks AI and OpenRouter providers. + +## Prerequisites + +- A [DeepSeek Platform](https://platform.deepseek.com/) account +- A DeepSeek API key from [platform.deepseek.com/api_keys](https://platform.deepseek.com/api_keys) +- A running Fabro server + +## Configure direct access + +The direct `deepseek` provider is enabled in the built-in catalog. Store its key in the target Fabro server vault: + +```bash +fabro provider login --provider deepseek + +# For a non-default remote server: +fabro provider login --server https://your-fabro.example --provider deepseek + +# Or set the vault token directly: +fabro secret set DEEPSEEK_API_KEY +fabro secret --server https://your-fabro.example set DEEPSEEK_API_KEY +``` + +Standalone SDK usage outside a Fabro server can use an env-backed credential source explicitly: + +```bash +export DEEPSEEK_API_KEY= +``` + +Fabro sends bearer-authenticated Chat Completions requests to `https://api.deepseek.com`. + +## Included models + +| Fabro model ID | DeepSeek API model ID | Context | Max output | Role | +|---|---|---:|---:|---| +| `deepseek-v4-flash` | `deepseek-v4-flash` | 1,048,576 | 384,000 | Provider default, small default, and connectivity probe; aliases `deepseek`, `deepseek-v4`, `deepseek-flash` | +| `deepseek-v4-pro` | `deepseek-v4-pro` | 1,048,576 | 384,000 | Higher-capability V4 model | + +Both models support text input, tool calling, native reasoning, streaming, JSON output, and automatic prompt caching. They do not support image input. Thinking mode is enabled by default. + +## Use DeepSeek models + +```bash +fabro model list --provider deepseek +fabro model test --provider deepseek --model deepseek-v4-flash --deep +fabro run workflow.fabro --provider deepseek --model deepseek +``` + +In workflow stylesheets: + +```dot title="workflow.fabro" +digraph Example { + graph [ + model_stylesheet=" + * { model: deepseek-v4-flash; } + .difficult { model: deepseek-v4-pro; } + " + ] + + start [shape=Mdiamond, label="Start"] + work [label="Implement", prompt="Implement and verify the requested change."] + exit [shape=Msquare, label="Exit"] + + start -> work -> exit +} +``` + +## Prompt caching and pricing + +DeepSeek applies prefix caching automatically. Fabro reads DeepSeek's `prompt_cache_hit_tokens` usage field and reports cache-read tokens separately from uncached input tokens. + +The built-in catalog uses DeepSeek's published prices per million tokens: + +| Model | Uncached input | Cache hit | Output | +|---|---:|---:|---:| +| `deepseek-v4-flash` | $0.14 | $0.0028 | $0.28 | +| `deepseek-v4-pro` | $0.435 | $0.003625 | $0.87 | + +DeepSeek does not return an in-band dollar cost. Fabro calculates an estimated cost from these catalog rates and the reported token buckets. + +## Use a gateway + +The `deepseek-v4-flash`, `deepseek-v4-pro`, `deepseek`, `deepseek-v4`, and `deepseek-flash` selectors are portable across direct DeepSeek, Fireworks AI, and OpenRouter routes. Use `--provider` or a provider-qualified model selector when you need a specific route. + +See the [Fireworks AI integration](/integrations/fireworks) and [OpenRouter integration](/integrations/openrouter) for gateway setup and provider-specific pricing. + +## Troubleshooting + +**"No API key configured"** — Store `DEEPSEEK_API_KEY` on the target server with `fabro provider login --provider deepseek`. The server runtime resolves the key from its vault, not from process env. + +**Unknown model** — Use `deepseek-v4-flash` or `deepseek-v4-pro`. The retired `deepseek-chat` and `deepseek-reasoner` API IDs are not in the Fabro catalog. + +**A tool continuation returns HTTP 400** — Keep the assistant thinking content in conversation history. Fabro does this automatically when it replays tool-call turns. + +## Further reading + + + + Official authentication, endpoints, and API reference. + + + Official limits, features, and token prices. + + diff --git a/docs/public/reference/sdk.mdx b/docs/public/reference/sdk.mdx index feeea0c0a..ad4eedb0b 100644 --- a/docs/public/reference/sdk.mdx +++ b/docs/public/reference/sdk.mdx @@ -371,6 +371,7 @@ For env-backed usage, `EnvCredentialSource` checks for API key environment varia | `MINIMAX_API_KEY` | Minimax | | `INCEPTION_API_KEY` | Inception | | `POOLSIDE_API_KEY` | Poolside | +| `DEEPSEEK_API_KEY` | DeepSeek | | `OPENROUTER_API_KEY` | OpenRouter, when enabled in settings | The first provider registered becomes the default. Provider base URLs come from the model catalog. For vault-backed usage inside Fabro, use `fabro_auth::VaultCredentialSource` instead. diff --git a/lib/apps/fabro-cli/src/commands/install.rs b/lib/apps/fabro-cli/src/commands/install.rs index 3486b35f5..adfb2d97c 100644 --- a/lib/apps/fabro-cli/src/commands/install.rs +++ b/lib/apps/fabro-cli/src/commands/install.rs @@ -3521,6 +3521,7 @@ root = "{}" assert!(ids.contains(&ProviderId::new("inception"))); assert!(ids.contains(&ProviderId::new("venice"))); assert!(ids.contains(&ProviderId::new("poolside"))); + assert!(ids.contains(&ProviderId::new("deepseek"))); assert!(!ids.contains(&ProviderId::new("fireworks"))); assert!(!ids.contains(&ProviderId::new("ollama"))); assert!(!ids.contains(&ProviderId::new("litellm"))); diff --git a/lib/components/fabro-llm/src/adapter_registry.rs b/lib/components/fabro-llm/src/adapter_registry.rs index 26ff6d70b..bb1b893ce 100644 --- a/lib/components/fabro-llm/src/adapter_registry.rs +++ b/lib/components/fabro-llm/src/adapter_registry.rs @@ -303,6 +303,8 @@ mod tests { ("claude-sonnet-4-5", "claude-sonnet-4-5", T::Anthropic, C::AnthropicMessages, B::Anthropic, P::Anthropic), ("claude-sonnet-4-6", "claude-sonnet-4-6", T::Anthropic, C::AnthropicMessages, B::Anthropic, P::Anthropic), ("claude-sonnet-5", "claude-sonnet-5", T::Anthropic, C::AnthropicMessages, B::Anthropic, P::Claude5), + ("deepseek-v4-flash", "deepseek-v4-flash", T::OpenAiCompatible, C::OpenAiCompatible, B::OpenAi, P::OpenAi), + ("deepseek-v4-pro", "deepseek-v4-pro", T::OpenAiCompatible, C::OpenAiCompatible, B::OpenAi, P::OpenAi), ("gemini-3-flash-preview", "gemini-3-flash-preview", T::Gemini, C::GeminiGenerate, B::Gemini, P::Gemini), ("gemini-3.1-flash-lite", "gemini-3.1-flash-lite", T::Gemini, C::GeminiGenerate, B::Gemini, P::Gemini), ("gemini-3.1-pro-preview", "gemini-3.1-pro-preview", T::Gemini, C::GeminiGenerate, B::Gemini, P::Gemini), diff --git a/lib/components/fabro-llm/src/codec/openai_compatible/wire.rs b/lib/components/fabro-llm/src/codec/openai_compatible/wire.rs index 3e1de949d..bc3883aa6 100644 --- a/lib/components/fabro-llm/src/codec/openai_compatible/wire.rs +++ b/lib/components/fabro-llm/src/codec/openai_compatible/wire.rs @@ -300,6 +300,10 @@ pub(super) struct ApiUsage { pub cost: Option, #[serde(default)] pub prompt_tokens_details: Option, + /// DeepSeek-specific top-level count of prompt tokens served from its + /// automatic context cache. + #[serde(default)] + pub prompt_cache_hit_tokens: Option, #[serde(default)] pub completion_tokens_details: Option, } @@ -329,6 +333,7 @@ impl ApiUsage { .prompt_tokens_details .as_ref() .and_then(|d| d.cached_tokens) + .or(self.prompt_cache_hit_tokens) .unwrap_or(0); let cache_write_detail = self .prompt_tokens_details @@ -538,6 +543,23 @@ mod tests { }); } + #[test] + fn token_counts_accept_deepseek_cache_hit_field() { + let usage: ApiUsage = serde_json::from_value(serde_json::json!({ + "prompt_tokens": 53, + "completion_tokens": 11, + "prompt_cache_hit_tokens": 41 + })) + .unwrap(); + + assert_eq!(usage.token_counts(), TokenCounts { + input_tokens: 12, + output_tokens: 11, + cache_read_tokens: 41, + ..TokenCounts::default() + }); + } + #[test] fn reasoning_accepts_provider_and_openrouter_spellings() { let provider_response: ApiResponse = serde_json::from_value(serde_json::json!({ diff --git a/lib/components/fabro-llm/tests/integration.rs b/lib/components/fabro-llm/tests/integration.rs index d543374eb..96b6adad8 100644 --- a/lib/components/fabro-llm/tests/integration.rs +++ b/lib/components/fabro-llm/tests/integration.rs @@ -599,6 +599,28 @@ async fn fireworks_complete() { assert_eq!(response.provider, "fireworks"); } +#[fabro_macros::e2e_test(live("DEEPSEEK_API_KEY"))] +async fn deepseek_complete() { + let api_key = std::env::var(EnvVars::DEEPSEEK_API_KEY).expect("DEEPSEEK_API_KEY must be set"); + let adapter = + OpenAiCompatibleAdapter::new(api_key, "https://api.deepseek.com").with_name("deepseek"); + let request = Request { + // Thinking mode is enabled by default and shares this budget with the + // visible answer. + max_tokens: Some(1024), + ..make_request("deepseek-v4-flash") + }; + let response = adapter.complete(&request).await.unwrap(); + + assert!( + !response.text().is_empty(), + "response text should not be empty" + ); + assert!(response.usage.input_tokens > 0); + assert!(response.usage.output_tokens > 0 || response.usage.reasoning_tokens > 0); + assert_eq!(response.provider, "deepseek"); +} + #[fabro_macros::e2e_test(live("FIREWORKS_API_KEY"))] async fn fireworks_kimi_k2_7_code_deep_tool_round_trip() { let api_key = std::env::var(EnvVars::FIREWORKS_API_KEY).expect("FIREWORKS_API_KEY must be set"); diff --git a/lib/foundation/fabro-model/src/catalog.rs b/lib/foundation/fabro-model/src/catalog.rs index 83d1a04bd..3eb647f0c 100644 --- a/lib/foundation/fabro-model/src/catalog.rs +++ b/lib/foundation/fabro-model/src/catalog.rs @@ -3028,6 +3028,77 @@ enabled = true ); } + #[test] + fn builtin_deepseek_provider_routes_v4_models() { + let deepseek = ProviderId::new("deepseek"); + let catalog = Catalog::builtin(); + let provider = catalog + .provider(&deepseek) + .expect("DeepSeek provider should be active"); + + assert_eq!(provider.adapter, AdapterKind::OpenAiCompatible); + assert_eq!(provider.codec, CodecKind::OpenAiCompatible); + assert_eq!(provider.billing_policy, BillingPolicy::OpenAi); + assert_eq!( + provider.base_url.as_deref(), + Some("https://api.deepseek.com") + ); + assert_eq!(provider.priority, 75); + assert_eq!(provider.auth.as_ref().unwrap().credentials, vec![ + CredentialRef::Env("DEEPSEEK_API_KEY".to_string()), + CredentialRef::Vault("DEEPSEEK_API_KEY".to_string()), + ]); + assert_eq!( + catalog + .default_for_provider(&deepseek) + .map(|model| model.id.as_str()), + Some("deepseek-v4-flash") + ); + assert_eq!( + catalog + .small_default_for_provider(&deepseek) + .map(|model| model.id.as_str()), + Some("deepseek-v4-flash") + ); + assert_eq!( + catalog + .probe_for_provider(&deepseek) + .map(|model| model.id.as_str()), + Some("deepseek-v4-flash") + ); + + let expected = [ + ("deepseek-v4-flash", 0.14, 0.28, 0.0028), + ("deepseek-v4-pro", 0.435, 0.87, 0.003625), + ]; + for (id, input, output, cache_read) in expected { + let model = catalog + .get_on_provider(&deepseek, id) + .unwrap_or_else(|| panic!("DeepSeek model '{id}' should be present")); + assert_eq!(model.family, "deepseek-v4", "{id}"); + assert_eq!(model.limits.context_window, 1_048_576, "{id}"); + assert_eq!(model.limits.max_output, Some(384_000), "{id}"); + assert!(model.features.tools, "{id}"); + assert!(!model.features.vision, "{id}"); + assert!(model.features.reasoning, "{id}"); + assert!(model.features.prompt_cache, "{id}"); + assert!(!model.features.sampling_params, "{id}"); + assert_eq!(model.costs.input_cost_per_mtok, Some(input), "{id}"); + assert_eq!(model.costs.output_cost_per_mtok, Some(output), "{id}"); + assert_eq!( + model.costs.cache_input_cost_per_mtok, + Some(cache_read), + "{id}" + ); + + let settings = catalog + .model_settings_on_provider(&deepseek, id) + .unwrap_or_else(|| panic!("DeepSeek settings for '{id}' should be present")); + assert_eq!(settings.api_id, id, "{id}"); + assert!(settings.reasoning_by_default, "{id}"); + } + } + #[test] fn builtin_openrouter_provider_is_opt_in() { let openrouter = ProviderId::new("openrouter"); @@ -4011,7 +4082,7 @@ enabled = true } #[test] - fn builtin_fireworks_shared_slugs_are_portable_with_openrouter() { + fn builtin_deepseek_shared_slugs_are_portable_across_providers() { let catalog = Catalog::from_builtin_with_overrides(&minimal_settings( r" [providers.fireworks] @@ -4037,7 +4108,20 @@ enabled = true assert_eq!(model.id, id, "{provider}/{id}"); assert_eq!(model.provider, provider, "{provider}/{id}"); } + } + for provider in [ + ProviderId::new("deepseek"), + ProviderId::new("fireworks"), + ProviderId::new("openrouter"), + ] { + for id in ["deepseek-v4-pro", "deepseek-v4-flash"] { + let model = catalog + .get_on_provider(&provider, id) + .unwrap_or_else(|| panic!("'{id}' should resolve on provider '{provider}'")); + assert_eq!(model.id, id, "{provider}/{id}"); + assert_eq!(model.provider, provider, "{provider}/{id}"); + } for alias in ["deepseek", "deepseek-v4", "deepseek-flash"] { let model = catalog .resolve_on_provider(&provider, alias) @@ -4048,6 +4132,19 @@ enabled = true assert_eq!(model.provider, provider, "{provider}/{alias}"); } } + + let selected = catalog + .select( + "deepseek", + None, + &HashSet::from([ + ProviderId::new("deepseek"), + ProviderId::new("fireworks"), + ProviderId::new("openrouter"), + ]), + ) + .expect("direct DeepSeek should win portable DeepSeek selection"); + assert_eq!(selected.provider, ProviderId::new("deepseek")); } #[test] diff --git a/lib/foundation/fabro-model/src/catalog/providers/deepseek.toml b/lib/foundation/fabro-model/src/catalog/providers/deepseek.toml new file mode 100644 index 000000000..f7b073d72 --- /dev/null +++ b/lib/foundation/fabro-model/src/catalog/providers/deepseek.toml @@ -0,0 +1,61 @@ +[providers.deepseek] +display_name = "DeepSeek" +adapter = "openai_compatible" +api_key_url = "https://platform.deepseek.com/api_keys" +base_url = "https://api.deepseek.com" +priority = 75 + +[providers.deepseek.auth] +credentials = ["env:DEEPSEEK_API_KEY", "vault:DEEPSEEK_API_KEY"] + +# DeepSeek V4 uses thinking mode by default. The API accepts sampling +# parameters in that mode but ignores them, so Fabro omits those parameters. +# Prompt caching is automatic and usage reports prompt_cache_hit_tokens. +# Prices are from api-docs.deepseek.com/quick_start/pricing, verified +# 2026-07-31. + +[providers.deepseek.models."deepseek-v4-flash"] +display_name = "DeepSeek V4 Flash" +family = "deepseek-v4" +aliases = ["deepseek-v4", "deepseek", "deepseek-flash"] +default = true +small_default = true +probe = true + +[providers.deepseek.models."deepseek-v4-flash".limits] +context_window = 1048576 +max_output = 384000 + +[providers.deepseek.models."deepseek-v4-flash".features] +tools = true +vision = false +reasoning = true +reasoning_by_default = true +prompt_cache = true +sampling_params = false + +[providers.deepseek.models."deepseek-v4-flash".costs] +input_cost_per_mtok = 0.14 +output_cost_per_mtok = 0.28 +cache_input_cost_per_mtok = 0.0028 + +[providers.deepseek.models."deepseek-v4-pro"] +display_name = "DeepSeek V4 Pro" +family = "deepseek-v4" + +[providers.deepseek.models."deepseek-v4-pro".limits] +context_window = 1048576 +max_output = 384000 + +[providers.deepseek.models."deepseek-v4-pro".features] +tools = true +vision = false +reasoning = true +reasoning_by_default = true +prompt_cache = true +sampling_params = false + +[providers.deepseek.models."deepseek-v4-pro".costs] +input_cost_per_mtok = 0.435 +output_cost_per_mtok = 0.87 +cache_input_cost_per_mtok = 0.003625 diff --git a/lib/foundation/fabro-static/src/env_vars.rs b/lib/foundation/fabro-static/src/env_vars.rs index 849ec6842..fc5d2312a 100644 --- a/lib/foundation/fabro-static/src/env_vars.rs +++ b/lib/foundation/fabro-static/src/env_vars.rs @@ -48,6 +48,7 @@ impl EnvVars { pub const BEDROCK_API_KEY: &'static str = "BEDROCK_API_KEY"; pub const BRAVE_SEARCH_API_KEY: &'static str = "BRAVE_SEARCH_API_KEY"; pub const CHATGPT_ACCOUNT_ID: &'static str = "CHATGPT_ACCOUNT_ID"; + pub const DEEPSEEK_API_KEY: &'static str = "DEEPSEEK_API_KEY"; pub const FIREWORKS_API_KEY: &'static str = "FIREWORKS_API_KEY"; pub const GEMINI_API_KEY: &'static str = "GEMINI_API_KEY"; pub const GEMINI_BASE_URL: &'static str = "GEMINI_BASE_URL"; @@ -198,6 +199,7 @@ mod tests { EnvVars::BEDROCK_API_KEY, EnvVars::BRAVE_SEARCH_API_KEY, EnvVars::CHATGPT_ACCOUNT_ID, + EnvVars::DEEPSEEK_API_KEY, EnvVars::FIREWORKS_API_KEY, EnvVars::GEMINI_API_KEY, EnvVars::GEMINI_BASE_URL, diff --git a/lib/foundation/fabro-static/src/secret_registry.rs b/lib/foundation/fabro-static/src/secret_registry.rs index 03dec8e12..3bfbf92be 100644 --- a/lib/foundation/fabro-static/src/secret_registry.rs +++ b/lib/foundation/fabro-static/src/secret_registry.rs @@ -19,6 +19,7 @@ const OPTIONAL_VAULT_SECRETS: &[&str] = &[ EnvVars::AWS_BEARER_TOKEN_BEDROCK, EnvVars::BEDROCK_API_KEY, EnvVars::BRAVE_SEARCH_API_KEY, + EnvVars::DEEPSEEK_API_KEY, EnvVars::FABRO_SLACK_APP_TOKEN, EnvVars::FABRO_SLACK_BOT_TOKEN, EnvVars::FIREWORKS_API_KEY, @@ -92,6 +93,7 @@ mod tests { EnvVars::ANTHROPIC_API_KEY, EnvVars::AWS_BEARER_TOKEN_BEDROCK, EnvVars::BEDROCK_API_KEY, + EnvVars::DEEPSEEK_API_KEY, EnvVars::FIREWORKS_API_KEY, EnvVars::GEMINI_API_KEY, EnvVars::INCEPTION_API_KEY,