Skip to content

Commit 5ea6adb

Browse files
Add specific error for missing required env vars in clients (BoundaryML#2570)
Issues: BoundaryML#2054 and BoundaryML#2055
1 parent a2f2b96 commit 5ea6adb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1582
-27
lines changed

engine/baml-runtime/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,10 @@ impl BamlRuntime {
10571057
stream: bool,
10581058
) -> Result<HTTPRequest> {
10591059
baml_log::set_from_env(&env_vars).unwrap();
1060-
let ctx = context_manager.create_ctx(tb, cb, env_vars, vec![])?;
1060+
let mut ctx = context_manager.create_ctx(tb, cb, env_vars, vec![])?;
1061+
1062+
// Called from modular API.
1063+
ctx.set_modular_api(true);
10611064

10621065
let provider = self.llm_provider_from_function(&function_name, &ctx)?;
10631066

engine/baml-runtime/src/runtime/runtime_interface.rs

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use internal_baml_core::{
1515
validate,
1616
};
1717
use internal_baml_jinja::RenderedPrompt;
18-
use internal_llm_client::{AllowedRoleMetadata, ClientSpec};
18+
use internal_llm_client::{AllowedRoleMetadata, ClientProvider, ClientSpec};
1919

2020
use crate::{
2121
client_registry::ClientProperty,
@@ -105,17 +105,46 @@ impl<'a> InternalClientLookup<'a> for InternalBamlRuntime {
105105
.context(format!("Could not find client with name: {client_name}"))?;
106106
// Get required env vars from the client walker
107107
let new_client = LLMProvider::try_from((&walker, ctx)).map(Arc::new)?;
108-
// Only store the required env vars
109-
let filtered_env_vars = ctx
110-
.env_vars()
111-
.iter()
112-
.filter(|(k, _)| walker.required_env_vars().contains(*k))
113-
.map(|(k, v)| (k.clone(), v.clone()))
114-
.collect();
108+
109+
// Collect required environment variables.
110+
let mut required_env_vars = HashMap::new();
111+
112+
// If the client is Vertex or AWS Bedrock, we don't fail on
113+
// missing required environment variables because we run a bunch
114+
// of additional logic to resolve required values (i.e for
115+
// Vertex if GOOGLE_CLOUD_PROJECT is not provided it can be
116+
// found on the credentials property).
117+
//
118+
// If called with modular API, we don't fail either. User might
119+
// want to insert the values later.
120+
let fail_on_missing_required_env_vars = !ctx.is_modular_api()
121+
&& !matches!(
122+
walker.item.elem.provider,
123+
ClientProvider::AwsBedrock | ClientProvider::Vertex
124+
);
125+
126+
for key in walker.required_env_vars() {
127+
if let Some(value) = ctx.env_vars().get(&key) {
128+
// Exists but is empty
129+
if fail_on_missing_required_env_vars && value.trim().is_empty() {
130+
baml_log::warn!(
131+
"Required environment variable '{key}' for client '{client_name}' is set but is empty: {key}='{value}'"
132+
);
133+
}
134+
required_env_vars.insert(key, value.to_owned());
135+
} else if fail_on_missing_required_env_vars {
136+
// It's not set and we have to fail, bail
137+
anyhow::bail!(
138+
"LLM client '{client_name}' requires environment variable '{key}' to be set but it is not"
139+
);
140+
}
141+
}
142+
115143
clients.insert(
116144
client_name.into(),
117-
CachedClient::new(new_client.clone(), filtered_env_vars),
145+
CachedClient::new(new_client.clone(), required_env_vars),
118146
);
147+
119148
Ok(new_client)
120149
}
121150
}

engine/baml-runtime/src/types/runtime_context.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ pub struct RuntimeContext {
6363
// Only the BAML_TRACER depends on this.
6464
pub call_id_stack: Vec<FunctionCallId>,
6565
pub recursive_class_overrides: Vec<IndexSet<String>>,
66+
/// Called through modular API.
67+
is_modular_api: bool,
6668
}
6769

6870
impl RuntimeContext {
@@ -78,6 +80,14 @@ impl RuntimeContext {
7880
self.env.get("BOUNDARY_PROXY_URL").map(|s| s.as_str())
7981
}
8082

83+
pub fn is_modular_api(&self) -> bool {
84+
self.is_modular_api
85+
}
86+
87+
pub fn set_modular_api(&mut self, is_modular_api: bool) {
88+
self.is_modular_api = is_modular_api;
89+
}
90+
8191
pub fn new(
8292
baml_src: Arc<BamlSrcReader>,
8393
env: HashMap<String, String>,
@@ -101,6 +111,7 @@ impl RuntimeContext {
101111
recursive_type_alias_overrides,
102112
call_id_stack,
103113
recursive_class_overrides,
114+
is_modular_api: false,
104115
}
105116
}
106117

integ-tests/baml_src/clients.baml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ client<llm> GPT4o {
3030
}
3131
}
3232

33+
// For integ tests
34+
client<llm> GPT4oBaseUrlNotSet {
35+
provider openai
36+
options {
37+
model gpt-4o
38+
api_key env.OPENAI_API_KEY
39+
base_url env.OPEN_API_BASE_DO_NOT_SET_THIS
40+
}
41+
}
42+
3343

3444
client<llm> GPT4Turbo {
3545
retry_policy Bar

integ-tests/baml_src/test-files/providers/openai.baml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ function TestOpenAIShorthand(input: string) -> string {
2828
"#
2929
}
3030

31-
32-
33-
31+
32+
33+
3434
// Test standard GPT-4 (should add default max_tokens)
3535
function TestOpenAI(input: string) -> string {
3636
client GPT4
@@ -39,7 +39,7 @@ function TestOpenAI(input: string) -> string {
3939
Write a nice haiku, given the user input. Make sure to reference the input in the haiku. Make it 50 paragraphs
4040

4141
Input: {{ input }}
42-
"#
42+
"#
4343
}
4444

4545
// Test O1 model without max_tokens (should not add default)
@@ -129,6 +129,14 @@ function TestOpenAIGPT4oMini3(input: string) -> string {
129129
"#
130130
}
131131

132+
function OpenAIGPT4oMissingBaseUrlEnvVar(input: string) -> string {
133+
client GPT4oBaseUrlNotSet
134+
prompt #"
135+
{{ _.role("user") }}
136+
Write a nice haiku, given the user input. Make sure to reference the input in the haiku.
137+
"#
138+
}
139+
132140
// Add test cases to verify the behavior
133141
test TestOpenAIClients {
134142
functions [

integ-tests/go/baml_client/baml_source_map.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integ-tests/go/baml_client/functions.go

Lines changed: 66 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integ-tests/go/baml_client/functions_parse.go

Lines changed: 47 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integ-tests/go/baml_client/functions_parse_stream.go

Lines changed: 47 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)