From 76956623aa2f4cf507f251ff319639cf4cc5d2a2 Mon Sep 17 00:00:00 2001 From: Anish Palakurthi <anish.palakurthi@gmail.com> Date: Mon, 8 Jul 2024 11:01:51 -0700 Subject: [PATCH 01/11] overrides media type if specified --- .../src/internal/llm_client/traits/mod.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs index cb07775ef..10fa7ccb6 100644 --- a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs +++ b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs @@ -91,12 +91,15 @@ where match part { ChatMessagePart::Image(BamlMedia::Url(_, media_url)) | ChatMessagePart::Audio(BamlMedia::Url(_, media_url)) => { - let (base64, mime_type) = if media_url.url.starts_with("data:") { + + + + let (base64, mut mime_type) = if media_url.url.starts_with("data:") { let parts: Vec<&str> = media_url.url.splitn(2, ',').collect(); let base64 = parts.get(1).unwrap().to_string(); let prefix = parts.get(0).unwrap(); - let mime_type = + let mut mime_type = prefix.splitn(2, ':').next().unwrap().to_string() .split('/').last().unwrap().to_string(); @@ -125,13 +128,17 @@ where }; let base64 = BASE64_STANDARD.encode(&bytes); let inferred_type = infer::get(&bytes); - let mime_type = inferred_type.map_or_else( + let mut mime_type = inferred_type.map_or_else( || "application/octet-stream".into(), |t| t.extension().into(), ); (base64, mime_type) }; + if let Some(media_type) = &media_url.media_type { + mime_type = media_type.clone(); + } + Ok(if matches!(part, ChatMessagePart::Image(_)) { ChatMessagePart::Image(BamlMedia::Base64( BamlMediaType::Image, From 03e81718b856a5691493ac2f098a8c7bf09c06d8 Mon Sep 17 00:00:00 2001 From: Anish Palakurthi <anish.palakurthi@gmail.com> Date: Mon, 8 Jul 2024 11:04:58 -0700 Subject: [PATCH 02/11] render defaults to stream=true --- .../playground-common/src/baml_wasm_web/EventListener.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index a456644fd..07a2fdeb1 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -360,7 +360,7 @@ const asyncCurlAtom = atom(async (get) => { .map((input) => [input.name, JSON.parse(input.value)]), ) try { - return await func.render_raw_curl(runtime, params, false) + return await func.render_raw_curl(runtime, params, true) } catch (e) { console.error(e) return 'Error rendering curl command' From 1daf88b2491aff63fbf4511f61c4d32064f2f0b5 Mon Sep 17 00:00:00 2001 From: Anish Palakurthi <anish.palakurthi@gmail.com> Date: Mon, 8 Jul 2024 11:13:14 -0700 Subject: [PATCH 03/11] updated curl error rendering --- .../src/internal/llm_client/primitive/aws/aws_client.rs | 2 +- .../playground-common/src/baml_wasm_web/EventListener.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/aws/aws_client.rs b/engine/baml-runtime/src/internal/llm_client/primitive/aws/aws_client.rs index cd80b9f5e..53a25062a 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/aws/aws_client.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/aws/aws_client.rs @@ -511,7 +511,7 @@ impl TryInto<bedrock::types::Message> for AwsChatMessage<'_> { ChatMessagePart::Image(media) | ChatMessagePart::Audio(media) => match media { BamlMedia::Url(_, _) => { anyhow::bail!( - "BAML internal error: media URL should have been resolved to base64" + "BAML internal error (AWSBedrock): media URL should have been resolved to base64" ) } BamlMedia::Base64(BamlMediaType::Image, media) => { diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index 07a2fdeb1..04b32dae0 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -360,10 +360,10 @@ const asyncCurlAtom = atom(async (get) => { .map((input) => [input.name, JSON.parse(input.value)]), ) try { - return await func.render_raw_curl(runtime, params, true) + return await func.render_raw_curl(runtime, params, false) } catch (e) { console.error(e) - return 'Error rendering curl command' + return `${e}` } }) From caf540b5ddf6af6d9bef18743f913cdf41305a25 Mon Sep 17 00:00:00 2001 From: Anish Palakurthi <anish.palakurthi@gmail.com> Date: Mon, 8 Jul 2024 11:47:50 -0700 Subject: [PATCH 04/11] fixed query params rendering for azure --- .../primitive/openai/openai_client.rs | 48 +++++++++---------- .../src/internal/llm_client/traits/mod.rs | 17 ++++--- .../baml-schema-wasm/src/runtime_wasm/mod.rs | 2 +- 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs b/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs index 8a956e66b..b06f0b1bd 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs @@ -216,30 +216,32 @@ impl RequestBuilder for OpenAIClient { prompt: either::Either<&String, &Vec<RenderedChatMessage>>, stream: bool, ) -> Result<reqwest::RequestBuilder> { - let mut req = self.client.post(if prompt.is_left() { - format!( - "{}/completions", - self.properties - .proxy_url - .as_ref() - .unwrap_or(&self.properties.base_url) - .clone() - ) - } else { - format!( - "{}/chat/completions", - self.properties - .proxy_url - .as_ref() - .unwrap_or(&self.properties.base_url) - .clone() - ) - }); + // Determine the base URL + let base_url = format!( + "{}/chat/completions", + self.properties + .proxy_url + .as_ref() + .unwrap_or(&self.properties.base_url) + .clone() + ); + // Construct the full URL with query parameters + let mut url = reqwest::Url::parse(&base_url)?; if !self.properties.query_params.is_empty() { - req = req.query(&self.properties.query_params); + { + let mut pairs = url.query_pairs_mut(); + for (key, value) in &self.properties.query_params { + pairs.append_pair(key, value); + } + } } + let full_url_with_query = url.to_string(); + // Create the request builder with the full URL + let mut req = self.client.post(full_url_with_query.clone()); + + // Add headers and other properties for (key, value) in &self.properties.headers { req = req.header(key, value); } @@ -247,11 +249,9 @@ impl RequestBuilder for OpenAIClient { req = req.bearer_auth(key) } req = req.header("baml-original-url", self.properties.base_url.as_str()); + req = req.header("baml-render-url", full_url_with_query); - req = req.header( - "baml-render-url", - format!("{}/chat/completions", self.properties.base_url), - ); + // Add the body let mut body = json!(self.properties.properties); let body_obj = body.as_object_mut().unwrap(); match prompt { diff --git a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs index 10fa7ccb6..a336ea68a 100644 --- a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs +++ b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs @@ -136,7 +136,7 @@ where }; if let Some(media_type) = &media_url.media_type { - mime_type = media_type.clone(); + mime_type = media_type.clone().split('/').last().unwrap().to_string(); } Ok(if matches!(part, ChatMessagePart::Image(_)) { @@ -423,18 +423,21 @@ where .ok_or(anyhow::anyhow!("Missing header 'baml-render-url'"))?; url_header_value.to_owned() }; + log::info!("url_header_value: {:?}", url_header_value); let url_str = url_header_value .to_str() .map_err(|_| anyhow::anyhow!("Invalid header 'baml-render-url'"))?; - let new_url = Url::from_str(url_str)?; + let mut new_url = Url::from_str(url_str)?; + new_url.set_query(request.url().query()); // Preserve query parameters + *request.url_mut() = new_url; - { - let headers = request.headers_mut(); - headers.remove("baml-original-url"); - headers.remove("baml-render-url"); - } + + let headers = request.headers_mut(); + headers.remove("baml-original-url"); + headers.remove("baml-render-url"); + let body = request .body() diff --git a/engine/baml-schema-wasm/src/runtime_wasm/mod.rs b/engine/baml-schema-wasm/src/runtime_wasm/mod.rs index a84141794..e9bb45163 100644 --- a/engine/baml-schema-wasm/src/runtime_wasm/mod.rs +++ b/engine/baml-schema-wasm/src/runtime_wasm/mod.rs @@ -21,7 +21,7 @@ use wasm_bindgen::prelude::*; #[wasm_bindgen(start)] pub fn on_wasm_init() { - match console_log::init_with_level(log::Level::Warn) { + match console_log::init_with_level(log::Level::Info) { Ok(_) => web_sys::console::log_1(&"Initialized BAML runtime logging".into()), Err(e) => web_sys::console::log_1( &format!("Failed to initialize BAML runtime logging: {:?}", e).into(), From 37a07a28918451a8b8e3512ca2f1c712ff28fe41 Mon Sep 17 00:00:00 2001 From: Anish Palakurthi <anish.palakurthi@gmail.com> Date: Mon, 8 Jul 2024 12:19:41 -0700 Subject: [PATCH 05/11] core changes done --- .../primitive/openai/openai_client.rs | 57 +++++++++++-------- .../src/internal/llm_client/traits/mod.rs | 3 +- .../src/runtime_wasm/runtime_prompt.rs | 4 -- .../src/baml_wasm_web/EventListener.tsx | 4 +- .../src/shared/FunctionPanel.tsx | 15 ++++- 5 files changed, 50 insertions(+), 33 deletions(-) diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs b/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs index b06f0b1bd..f4767acc9 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs @@ -216,32 +216,33 @@ impl RequestBuilder for OpenAIClient { prompt: either::Either<&String, &Vec<RenderedChatMessage>>, stream: bool, ) -> Result<reqwest::RequestBuilder> { - // Determine the base URL - let base_url = format!( - "{}/chat/completions", - self.properties - .proxy_url - .as_ref() - .unwrap_or(&self.properties.base_url) - .clone() - ); + let mut req = self.client.post(if prompt.is_left() { + format!( + "{}/completions", + self.properties + .proxy_url + .as_ref() + .unwrap_or(&self.properties.base_url) + .clone() + ) + } else { + format!( + "{}/chat/completions", + self.properties + .proxy_url + .as_ref() + .unwrap_or(&self.properties.base_url) + .clone() + ) + }); + + log::info!("Base url: {}", &self.properties.base_url); + log::info!("Proxy url: {:?}", &self.properties.proxy_url); - // Construct the full URL with query parameters - let mut url = reqwest::Url::parse(&base_url)?; if !self.properties.query_params.is_empty() { - { - let mut pairs = url.query_pairs_mut(); - for (key, value) in &self.properties.query_params { - pairs.append_pair(key, value); - } - } + req = req.query(&self.properties.query_params); } - let full_url_with_query = url.to_string(); - - // Create the request builder with the full URL - let mut req = self.client.post(full_url_with_query.clone()); - // Add headers and other properties for (key, value) in &self.properties.headers { req = req.header(key, value); } @@ -249,9 +250,19 @@ impl RequestBuilder for OpenAIClient { req = req.bearer_auth(key) } req = req.header("baml-original-url", self.properties.base_url.as_str()); + + let mut url = + reqwest::Url::parse(&format!("{}/chat/completions", self.properties.base_url))?; + { + let mut pairs = url.query_pairs_mut(); + for (key, value) in &self.properties.query_params { + pairs.append_pair(key, value); + } + } + let full_url_with_query = url.to_string(); + req = req.header("baml-render-url", full_url_with_query); - // Add the body let mut body = json!(self.properties.properties); let body_obj = body.as_object_mut().unwrap(); match prompt { diff --git a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs index a336ea68a..5c97e4de6 100644 --- a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs +++ b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs @@ -410,7 +410,7 @@ where stream: bool, ) -> Result<String> { let rendered_prompt = RenderedPrompt::Chat(prompt.clone()); - + log::info!("Stream is {}", stream); let chat_messages = self.curl_call(ctx, &rendered_prompt).await?; let request_builder = self .build_request(either::Right(&chat_messages), stream) @@ -423,7 +423,6 @@ where .ok_or(anyhow::anyhow!("Missing header 'baml-render-url'"))?; url_header_value.to_owned() }; - log::info!("url_header_value: {:?}", url_header_value); let url_str = url_header_value .to_str() diff --git a/engine/baml-schema-wasm/src/runtime_wasm/runtime_prompt.rs b/engine/baml-schema-wasm/src/runtime_wasm/runtime_prompt.rs index 2be7177e1..9712a42fb 100644 --- a/engine/baml-schema-wasm/src/runtime_wasm/runtime_prompt.rs +++ b/engine/baml-schema-wasm/src/runtime_wasm/runtime_prompt.rs @@ -110,10 +110,6 @@ impl WasmPrompt { #[wasm_bindgen] pub fn as_chat(&self) -> Option<Vec<WasmChatMessage>> { if let RenderedPrompt::Chat(s) = &self.prompt { - log::info!( - "Chat role: {:?}", - s.iter().map(|m| m.role.clone()).collect::<Vec<_>>() - ); Some( s.iter() .map(|m| WasmChatMessage { diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index 04b32dae0..80d9be506 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -346,6 +346,8 @@ export const availableFunctionsAtom = atom((get) => { return runtime.list_functions() }) +export const streamCurl = atom(true) + const asyncCurlAtom = atom(async (get) => { const runtime = get(selectedRuntimeAtom) const func = get(selectedFunctionAtom) @@ -360,7 +362,7 @@ const asyncCurlAtom = atom(async (get) => { .map((input) => [input.name, JSON.parse(input.value)]), ) try { - return await func.render_raw_curl(runtime, params, false) + return await func.render_raw_curl(runtime, params, get(streamCurl)) } catch (e) { console.error(e) return `${e}` diff --git a/typescript/playground-common/src/shared/FunctionPanel.tsx b/typescript/playground-common/src/shared/FunctionPanel.tsx index 02b37a340..ce823a58d 100644 --- a/typescript/playground-common/src/shared/FunctionPanel.tsx +++ b/typescript/playground-common/src/shared/FunctionPanel.tsx @@ -1,7 +1,7 @@ /// Content once a function has been selected. import { useAppState } from './AppStateContext' import { useAtomValue, useSetAtom } from 'jotai' -import { renderPromptAtom, selectedFunctionAtom, curlAtom } from '../baml_wasm_web/EventListener' +import { renderPromptAtom, selectedFunctionAtom, curlAtom, streamCurl } from '../baml_wasm_web/EventListener' import TestResults from '../baml_wasm_web/test_uis/test_result' import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '../components/ui/resizable' import { TooltipProvider } from '../components/ui/tooltip' @@ -10,6 +10,7 @@ import FunctionTestSnippet from './TestSnippet' import { Copy } from 'lucide-react' import { Button } from '../components/ui/button' import { CheckboxHeader } from './CheckboxHeader' +import { Switch } from '../components/ui/switch' import CustomErrorBoundary from '../utils/ErrorFallback' const handleCopy = (text: string) => () => { navigator.clipboard.writeText(text) @@ -20,10 +21,18 @@ const CurlSnippet: React.FC = () => { return ( <div> - <div className='flex justify-end'> + <div className='flex justify-end items-center space-x-2 p-2 rounded-md shadow-sm'> + <label className='flex items-center space-x-1 mr-2'> + <Switch + className='data-[state=checked]:bg-vscode-button-background' + checked={useAtomValue(streamCurl)} + onCheckedChange={useSetAtom(streamCurl)} + /> + <span>View Stream Request</span> + </label> <Button onClick={handleCopy(rawCurl)} - className='py-0 m-0 text-xs text-white bg-transparent copy-button hover:bg-indigo-500' + className='py-1 px-3 text-xs text-white bg-indigo-600 rounded-md hover:bg-indigo-500' > <Copy size={16} /> </Button> From fa9eb62cde92410fda613450dc56213bfadc900d Mon Sep 17 00:00:00 2001 From: Anish Palakurthi <anish.palakurthi@gmail.com> Date: Mon, 8 Jul 2024 12:23:48 -0700 Subject: [PATCH 06/11] log removals --- .../src/internal/llm_client/primitive/openai/openai_client.rs | 3 --- engine/baml-runtime/src/internal/llm_client/traits/mod.rs | 4 ++-- engine/baml-schema-wasm/src/runtime_wasm/mod.rs | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs b/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs index f4767acc9..c3e348567 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs @@ -236,9 +236,6 @@ impl RequestBuilder for OpenAIClient { ) }); - log::info!("Base url: {}", &self.properties.base_url); - log::info!("Proxy url: {:?}", &self.properties.proxy_url); - if !self.properties.query_params.is_empty() { req = req.query(&self.properties.query_params); } diff --git a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs index 5c97e4de6..69f23abef 100644 --- a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs +++ b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs @@ -410,7 +410,7 @@ where stream: bool, ) -> Result<String> { let rendered_prompt = RenderedPrompt::Chat(prompt.clone()); - log::info!("Stream is {}", stream); + let chat_messages = self.curl_call(ctx, &rendered_prompt).await?; let request_builder = self .build_request(either::Right(&chat_messages), stream) @@ -428,7 +428,7 @@ where .to_str() .map_err(|_| anyhow::anyhow!("Invalid header 'baml-render-url'"))?; let mut new_url = Url::from_str(url_str)?; - new_url.set_query(request.url().query()); // Preserve query parameters + *request.url_mut() = new_url; diff --git a/engine/baml-schema-wasm/src/runtime_wasm/mod.rs b/engine/baml-schema-wasm/src/runtime_wasm/mod.rs index e9bb45163..a84141794 100644 --- a/engine/baml-schema-wasm/src/runtime_wasm/mod.rs +++ b/engine/baml-schema-wasm/src/runtime_wasm/mod.rs @@ -21,7 +21,7 @@ use wasm_bindgen::prelude::*; #[wasm_bindgen(start)] pub fn on_wasm_init() { - match console_log::init_with_level(log::Level::Info) { + match console_log::init_with_level(log::Level::Warn) { Ok(_) => web_sys::console::log_1(&"Initialized BAML runtime logging".into()), Err(e) => web_sys::console::log_1( &format!("Failed to initialize BAML runtime logging: {:?}", e).into(), From c5ef27907b8990bd85d0f3c16f03a641cd06fbb7 Mon Sep 17 00:00:00 2001 From: Anish Palakurthi <anish.palakurthi@gmail.com> Date: Mon, 8 Jul 2024 15:00:36 -0700 Subject: [PATCH 07/11] simplified url rendering logic --- .../primitive/anthropic/anthropic_client.rs | 37 ++++++---------- .../llm_client/primitive/aws/aws_client.rs | 1 + .../primitive/google/google_client.rs | 38 ++++++++++------ .../primitive/openai/openai_client.rs | 43 +++++++------------ .../internal/llm_client/primitive/request.rs | 3 +- .../src/internal/llm_client/traits/mod.rs | 23 +++------- .../packages/vscode/src/extension.ts | 2 +- 7 files changed, 64 insertions(+), 83 deletions(-) diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs b/engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs index 2483569fe..adc7a469e 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs @@ -335,26 +335,21 @@ impl RequestBuilder for AnthropicClient { async fn build_request( &self, prompt: either::Either<&String, &Vec<RenderedChatMessage>>, + should_proxy: bool, stream: bool, ) -> Result<reqwest::RequestBuilder> { + let destiniation_url = if should_proxy { + self.properties + .proxy_url + .as_ref() + .unwrap_or(&self.properties.base_url) + } else { + &self.properties.base_url + }; let mut req = self.client.post(if prompt.is_left() { - format!( - "{}/v1/complete", - self.properties - .proxy_url - .as_ref() - .unwrap_or(&self.properties.base_url) - .clone() - ) + format!("{}/v1/complete", destiniation_url) } else { - format!( - "{}/v1/messages", - self.properties - .proxy_url - .as_ref() - .unwrap_or(&self.properties.base_url) - .clone() - ) + format!("{}/v1/messages", destiniation_url) }); for (key, value) in &self.properties.headers { @@ -364,12 +359,9 @@ impl RequestBuilder for AnthropicClient { req = req.header("x-api-key", key); } - req = req.header("baml-original-url", self.properties.base_url.as_str()); - req = req.header( - "baml-render-url", - format!("{}/v1/messages", self.properties.base_url), - ); - + if should_proxy { + req = req.header("baml-original-url", self.properties.base_url.as_str()); + } let mut body = json!(self.properties.properties); let body_obj = body.as_object_mut().unwrap(); match prompt { @@ -384,7 +376,6 @@ impl RequestBuilder for AnthropicClient { if stream { body_obj.insert("stream".into(), true.into()); } - log::debug!("Request body: {:#?}", body); Ok(req.json(&body)) } diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/aws/aws_client.rs b/engine/baml-runtime/src/internal/llm_client/primitive/aws/aws_client.rs index 53a25062a..bec74bcac 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/aws/aws_client.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/aws/aws_client.rs @@ -205,6 +205,7 @@ impl AwsClient { fn build_request( &self, ctx: &RuntimeContext, + chat_messages: &Vec<RenderedChatMessage>, ) -> Result<bedrock::operation::converse::ConverseInput> { let mut system_message = None; diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/google/google_client.rs b/engine/baml-runtime/src/internal/llm_client/primitive/google/google_client.rs index 85dedf265..40a4dc0b5 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/google/google_client.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/google/google_client.rs @@ -276,6 +276,7 @@ impl RequestBuilder for GoogleClient { async fn build_request( &self, prompt: either::Either<&String, &Vec<RenderedChatMessage>>, + should_proxy: bool, stream: bool, ) -> Result<reqwest::RequestBuilder> { let mut should_stream = "generateContent"; @@ -283,27 +284,38 @@ impl RequestBuilder for GoogleClient { should_stream = "streamGenerateContent?alt=sse"; } - let baml_original_url = format!( - "{}/models/{}:{}", - self.properties.base_url, - self.properties.model_id.as_ref().unwrap_or(&"".to_string()), - should_stream - ); - - let mut req = self.client.post( + let destination_url = if should_proxy { self.properties .proxy_url .as_ref() - .unwrap_or(&baml_original_url) - .clone(), - ); + .unwrap_or(&"".to_string()) + .clone() + } else { + format!( + "{}/models/{}:{}", + self.properties.base_url, + self.properties.model_id.as_ref().unwrap_or(&"".to_string()), + should_stream + ) + }; + + let mut req = self.client.post(destination_url); for (key, value) in &self.properties.headers { req = req.header(key, value); } - req = req.header("baml-original-url", baml_original_url.clone()); - req = req.header("baml-render-url", baml_original_url); + if should_proxy { + let baml_original_url = format!( + "{}/models/{}:{}", + self.properties.base_url, + self.properties.model_id.as_ref().unwrap_or(&"".to_string()), + should_stream + ); + + req = req.header("baml-original-url", baml_original_url.clone()); + } + req = req.header( "x-goog-api-key", self.properties diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs b/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs index c3e348567..d0d742e18 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs @@ -214,26 +214,22 @@ impl RequestBuilder for OpenAIClient { async fn build_request( &self, prompt: either::Either<&String, &Vec<RenderedChatMessage>>, + should_proxy: bool, + stream: bool, ) -> Result<reqwest::RequestBuilder> { + let destination_url = if should_proxy { + self.properties + .proxy_url + .as_ref() + .unwrap_or(&self.properties.base_url) + } else { + &self.properties.base_url + }; let mut req = self.client.post(if prompt.is_left() { - format!( - "{}/completions", - self.properties - .proxy_url - .as_ref() - .unwrap_or(&self.properties.base_url) - .clone() - ) + format!("{}/completions", destination_url) } else { - format!( - "{}/chat/completions", - self.properties - .proxy_url - .as_ref() - .unwrap_or(&self.properties.base_url) - .clone() - ) + format!("{}/chat/completions", destination_url) }); if !self.properties.query_params.is_empty() { @@ -246,19 +242,10 @@ impl RequestBuilder for OpenAIClient { if let Some(key) = &self.properties.api_key { req = req.bearer_auth(key) } - req = req.header("baml-original-url", self.properties.base_url.as_str()); - - let mut url = - reqwest::Url::parse(&format!("{}/chat/completions", self.properties.base_url))?; - { - let mut pairs = url.query_pairs_mut(); - for (key, value) in &self.properties.query_params { - pairs.append_pair(key, value); - } - } - let full_url_with_query = url.to_string(); - req = req.header("baml-render-url", full_url_with_query); + if should_proxy { + req = req.header("baml-original-url", self.properties.base_url.as_str()); + } let mut body = json!(self.properties.properties); let body_obj = body.as_object_mut().unwrap(); diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/request.rs b/engine/baml-runtime/src/internal/llm_client/primitive/request.rs index bc31c9f53..a06f0bd86 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/request.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/request.rs @@ -12,6 +12,7 @@ pub trait RequestBuilder { async fn build_request( &self, prompt: either::Either<&String, &Vec<RenderedChatMessage>>, + should_proxy: bool, stream: bool, ) -> Result<reqwest::RequestBuilder>; @@ -38,7 +39,7 @@ pub async fn make_request( log::debug!("Making request using client {}", client.context().name); let req = match client - .build_request(prompt, stream) + .build_request(prompt, true, stream) .await .context("Failed to build request") { diff --git a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs index 69f23abef..be9ded634 100644 --- a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs +++ b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs @@ -413,36 +413,25 @@ where let chat_messages = self.curl_call(ctx, &rendered_prompt).await?; let request_builder = self - .build_request(either::Right(&chat_messages), stream) + .build_request(either::Right(&chat_messages),false, stream) .await?; - let mut request = request_builder.build()?; + let request: reqwest::Request = request_builder.build()?; let url_header_value = { - let headers = request.headers_mut(); - let url_header_value = headers - .get("baml-render-url") - .ok_or(anyhow::anyhow!("Missing header 'baml-render-url'"))?; + + let url_header_value = request.url(); url_header_value.to_owned() }; let url_str = url_header_value - .to_str() - .map_err(|_| anyhow::anyhow!("Invalid header 'baml-render-url'"))?; - let mut new_url = Url::from_str(url_str)?; + .to_string(); - - *request.url_mut() = new_url; - - - let headers = request.headers_mut(); - headers.remove("baml-original-url"); - headers.remove("baml-render-url"); let body = request .body() .map(|b| b.as_bytes().unwrap_or_default().to_vec()) .unwrap_or_default(); // Add this line to handle the Option - let request_str = to_curl_command(url_str, "POST", request.headers(), body); + let request_str = to_curl_command(url_str.as_str(), "POST", request.headers(), body); Ok(request_str) } diff --git a/typescript/vscode-ext/packages/vscode/src/extension.ts b/typescript/vscode-ext/packages/vscode/src/extension.ts index 6ab474f90..7cb94b5e8 100644 --- a/typescript/vscode-ext/packages/vscode/src/extension.ts +++ b/typescript/vscode-ext/packages/vscode/src/extension.ts @@ -204,7 +204,7 @@ export function activate(context: vscode.ExtensionContext) { let originalUrl = req.headers['baml-original-url'] if (typeof originalUrl === 'string') { delete req.headers['baml-original-url'] - delete req.headers['baml-render-url'] + req.headers['origin'] = `http://localhost:${port}` // Ensure the URL does not end with a slash From d658c19c83ee7aea02cb6b2fafc701a35cc7e901 Mon Sep 17 00:00:00 2001 From: Anish Palakurthi <anish.palakurthi@gmail.com> Date: Mon, 8 Jul 2024 15:02:14 -0700 Subject: [PATCH 08/11] spelling --- .../llm_client/primitive/anthropic/anthropic_client.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs b/engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs index adc7a469e..345c05cb1 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs @@ -338,7 +338,7 @@ impl RequestBuilder for AnthropicClient { should_proxy: bool, stream: bool, ) -> Result<reqwest::RequestBuilder> { - let destiniation_url = if should_proxy { + let destination_url = if should_proxy { self.properties .proxy_url .as_ref() @@ -347,9 +347,9 @@ impl RequestBuilder for AnthropicClient { &self.properties.base_url }; let mut req = self.client.post(if prompt.is_left() { - format!("{}/v1/complete", destiniation_url) + format!("{}/v1/complete", destination_url) } else { - format!("{}/v1/messages", destiniation_url) + format!("{}/v1/messages", destination_url) }); for (key, value) in &self.properties.headers { From d2c4dd088dfc3e6a9590796c50263643b913b2bc Mon Sep 17 00:00:00 2001 From: Anish Palakurthi <anish.palakurthi@gmail.com> Date: Mon, 8 Jul 2024 15:16:06 -0700 Subject: [PATCH 09/11] style changes for buttons --- .../llm_client/primitive/anthropic/anthropic_client.rs | 6 +++--- .../internal/llm_client/primitive/google/google_client.rs | 6 +++--- .../internal/llm_client/primitive/openai/openai_client.rs | 6 +++--- .../src/internal/llm_client/primitive/request.rs | 2 +- typescript/fiddle-frontend/app/globals.css | 2 +- typescript/playground-common/src/shared/FunctionPanel.tsx | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs b/engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs index 345c05cb1..bae08a9c7 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs @@ -335,10 +335,10 @@ impl RequestBuilder for AnthropicClient { async fn build_request( &self, prompt: either::Either<&String, &Vec<RenderedChatMessage>>, - should_proxy: bool, + allow_proxy: bool, stream: bool, ) -> Result<reqwest::RequestBuilder> { - let destination_url = if should_proxy { + let destination_url = if allow_proxy { self.properties .proxy_url .as_ref() @@ -359,7 +359,7 @@ impl RequestBuilder for AnthropicClient { req = req.header("x-api-key", key); } - if should_proxy { + if allow_proxy { req = req.header("baml-original-url", self.properties.base_url.as_str()); } let mut body = json!(self.properties.properties); diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/google/google_client.rs b/engine/baml-runtime/src/internal/llm_client/primitive/google/google_client.rs index 40a4dc0b5..0cc977d5b 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/google/google_client.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/google/google_client.rs @@ -276,7 +276,7 @@ impl RequestBuilder for GoogleClient { async fn build_request( &self, prompt: either::Either<&String, &Vec<RenderedChatMessage>>, - should_proxy: bool, + allow_proxy: bool, stream: bool, ) -> Result<reqwest::RequestBuilder> { let mut should_stream = "generateContent"; @@ -284,7 +284,7 @@ impl RequestBuilder for GoogleClient { should_stream = "streamGenerateContent?alt=sse"; } - let destination_url = if should_proxy { + let destination_url = if allow_proxy { self.properties .proxy_url .as_ref() @@ -305,7 +305,7 @@ impl RequestBuilder for GoogleClient { req = req.header(key, value); } - if should_proxy { + if allow_proxy { let baml_original_url = format!( "{}/models/{}:{}", self.properties.base_url, diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs b/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs index d0d742e18..b7fde1766 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs @@ -214,11 +214,11 @@ impl RequestBuilder for OpenAIClient { async fn build_request( &self, prompt: either::Either<&String, &Vec<RenderedChatMessage>>, - should_proxy: bool, + allow_proxy: bool, stream: bool, ) -> Result<reqwest::RequestBuilder> { - let destination_url = if should_proxy { + let destination_url = if allow_proxy { self.properties .proxy_url .as_ref() @@ -243,7 +243,7 @@ impl RequestBuilder for OpenAIClient { req = req.bearer_auth(key) } - if should_proxy { + if allow_proxy { req = req.header("baml-original-url", self.properties.base_url.as_str()); } diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/request.rs b/engine/baml-runtime/src/internal/llm_client/primitive/request.rs index a06f0bd86..c8a769307 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/request.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/request.rs @@ -12,7 +12,7 @@ pub trait RequestBuilder { async fn build_request( &self, prompt: either::Either<&String, &Vec<RenderedChatMessage>>, - should_proxy: bool, + allow_proxy: bool, stream: bool, ) -> Result<reqwest::RequestBuilder>; diff --git a/typescript/fiddle-frontend/app/globals.css b/typescript/fiddle-frontend/app/globals.css index dec2545ce..19d87e3fb 100644 --- a/typescript/fiddle-frontend/app/globals.css +++ b/typescript/fiddle-frontend/app/globals.css @@ -84,7 +84,7 @@ /* controls dropdown styling on rsjf */ .form-control { - @apply bg-vscode-input-background text-vscode-input-foreground rounded-sm; +@apply bg-vscode-input-background text-vscode-input-foreground rounded-sm; } .array-item { diff --git a/typescript/playground-common/src/shared/FunctionPanel.tsx b/typescript/playground-common/src/shared/FunctionPanel.tsx index ce823a58d..20e2c085b 100644 --- a/typescript/playground-common/src/shared/FunctionPanel.tsx +++ b/typescript/playground-common/src/shared/FunctionPanel.tsx @@ -24,7 +24,7 @@ const CurlSnippet: React.FC = () => { <div className='flex justify-end items-center space-x-2 p-2 rounded-md shadow-sm'> <label className='flex items-center space-x-1 mr-2'> <Switch - className='data-[state=checked]:bg-vscode-button-background' + className='data-[state=checked]:bg-vscode-button-background data-[state=unchecked]:bg-vscode-input-background' checked={useAtomValue(streamCurl)} onCheckedChange={useSetAtom(streamCurl)} /> @@ -32,7 +32,7 @@ const CurlSnippet: React.FC = () => { </label> <Button onClick={handleCopy(rawCurl)} - className='py-1 px-3 text-xs text-white bg-indigo-600 rounded-md hover:bg-indigo-500' + className='py-1 px-3 text-xs text-white bg-vscode-button-background hover:bg-vscode-button-hoverBackground' > <Copy size={16} /> </Button> From 7b327ce3e37741851560c7115c50bcc06af52780 Mon Sep 17 00:00:00 2001 From: Anish Palakurthi <anish.palakurthi@gmail.com> Date: Mon, 8 Jul 2024 15:29:15 -0700 Subject: [PATCH 10/11] proxying media curls --- .../src/internal/llm_client/traits/mod.rs | 461 ++++++------------ .../input/named-args/single/named-image.baml | 2 +- integ-tests/python/baml_client/inlinedbaml.py | 2 +- integ-tests/ruby/baml_client/inlined.rb | 2 +- .../typescript/baml_client/inlinedbaml.ts | 2 +- 5 files changed, 154 insertions(+), 315 deletions(-) diff --git a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs index be9ded634..40e3bc926 100644 --- a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs +++ b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs @@ -13,7 +13,7 @@ use super::{primitive::request::RequestBuilder, LLMResponse, ModelFeatures}; use crate::{internal::prompt_renderer::PromptRenderer, RuntimeContext}; use baml_types::{BamlMedia, BamlMediaType, BamlValue, MediaBase64}; use base64::{prelude::BASE64_STANDARD, Engine}; -use futures::stream::{StreamExt, TryStreamExt}; +use futures::stream::StreamExt; use infer; use internal_baml_core::ir::repr::IntermediateRepr; use internal_baml_jinja::{ChatMessagePart, RenderedChatMessage}; @@ -83,111 +83,10 @@ where async fn single_call(&self, ctx: &RuntimeContext, prompt: &RenderedPrompt) -> LLMResponse { if self.model_features().resolve_media_urls { if let RenderedPrompt::Chat(ref chat) = prompt { - let messages_result = futures::stream::iter(chat.iter().map(|p| { - let new_parts = p - .parts - .iter() - .map(|part| async move { - match part { - ChatMessagePart::Image(BamlMedia::Url(_, media_url)) - | ChatMessagePart::Audio(BamlMedia::Url(_, media_url)) => { - - - - let (base64, mut mime_type) = if media_url.url.starts_with("data:") { - let parts: Vec<&str> = - media_url.url.splitn(2, ',').collect(); - let base64 = parts.get(1).unwrap().to_string(); - let prefix = parts.get(0).unwrap(); - let mut mime_type = - prefix.splitn(2, ':').next().unwrap().to_string() - .split('/').last().unwrap().to_string(); - - (base64, mime_type) - } else { - let client = reqwest::Client::new(); - let response = match client.get(&media_url.url) - // NB(sam): this would workaround CORS issues, but https://github.com/seanmonstar/reqwest/issues/1401 - //.fetch_mode_no_cors() - .send().await - { - Ok(response) => response, - Err(e) => { - return Err(LLMResponse::OtherFailure( - format!("Failed to fetch image due to CORS issue: {e:?}") - )) - } // replace with your error conversion logic - }; - let bytes = match response.bytes().await { - Ok(bytes) => bytes, - Err(e) => { - return Err(LLMResponse::OtherFailure( - e.to_string(), - )); - } // replace with your error conversion logic - }; - let base64 = BASE64_STANDARD.encode(&bytes); - let inferred_type = infer::get(&bytes); - let mut mime_type = inferred_type.map_or_else( - || "application/octet-stream".into(), - |t| t.extension().into(), - ); - (base64, mime_type) - }; - - if let Some(media_type) = &media_url.media_type { - mime_type = media_type.clone().split('/').last().unwrap().to_string(); - } - - Ok(if matches!(part, ChatMessagePart::Image(_)) { - ChatMessagePart::Image(BamlMedia::Base64( - BamlMediaType::Image, - MediaBase64 { - base64: base64, - media_type: format!("image/{}", mime_type), - }, - )) - } else { - ChatMessagePart::Audio(BamlMedia::Base64( - BamlMediaType::Audio, - MediaBase64 { - base64: base64, - media_type: format!("audio/{}", mime_type), - }, - )) - }) - } - _ => Ok(part.clone()), - } - }) - .collect::<Vec<_>>(); - async move { - let new_parts = futures::stream::iter(new_parts) - .then(|f| f) - .collect::<Vec<_>>() - .await; - - let new_parts = new_parts.into_iter().collect::<Result<Vec<_>, _>>()?; - - Ok::<_, anyhow::Error>(RenderedChatMessage { - role: p.role.clone(), - parts: new_parts, - }) - } - })) - .then(|f| f) - .collect::<Vec<_>>() - .await - .into_iter() - .collect::<Result<Vec<_>, _>>(); - - let messages = match messages_result { - Ok(messages) => messages, - Err(e) => { - return LLMResponse::OtherFailure(format!("Error occurred: {}", e)); - } - }; - return self.chat(ctx, &messages).await; + match process_media_urls(ctx, chat).await { + Ok(messages) => return self.chat(ctx, &messages).await, + Err(e) => return LLMResponse::OtherFailure(format!("Error occurred: {}", e)), + } } } @@ -210,102 +109,9 @@ where ) -> Result<Vec<RenderedChatMessage>, LLMResponse> { if self.model_features().resolve_media_urls { if let RenderedPrompt::Chat(ref chat) = prompt { - let messages_result = futures::stream::iter(chat.iter().map(|p| { - let new_parts = p - .parts - .iter() - .map(|part| async move { - match part { - ChatMessagePart::Image(BamlMedia::Url(_, media_url)) - | ChatMessagePart::Audio(BamlMedia::Url(_, media_url)) => { - let mut base64 = "".to_string(); - let mut mime_type = "".to_string(); - if media_url.url.starts_with("data:") { - let parts: Vec<&str> = - media_url.url.splitn(2, ',').collect(); - base64 = parts.get(1).unwrap().to_string(); - let prefix = parts.get(0).unwrap(); - mime_type = - prefix.splitn(2, ':').next().unwrap().to_string(); - mime_type = - mime_type.split('/').last().unwrap().to_string(); - } else { - let client = reqwest::Client::new(); - let response = match client.get(&media_url.url).send().await - { - Ok(response) => response, - Err(e) => { - return Err(LLMResponse::OtherFailure( - "Failed to fetch image due to CORS issue" - .to_string(), - )) - } // replace with your error conversion logic - }; - let bytes = match response.bytes().await { - Ok(bytes) => bytes, - Err(e) => { - return Err(LLMResponse::OtherFailure( - e.to_string(), - )) - } // replace with your error conversion logic - }; - base64 = BASE64_STANDARD.encode(&bytes); - let inferred_type = infer::get(&bytes); - mime_type = inferred_type.map_or_else( - || "application/octet-stream".into(), - |t| t.extension().into(), - ); - } - - Ok(if matches!(part, ChatMessagePart::Image(_)) { - ChatMessagePart::Image(BamlMedia::Base64( - BamlMediaType::Image, - MediaBase64 { - base64: base64, - media_type: format!("image/{}", mime_type), - }, - )) - } else { - ChatMessagePart::Audio(BamlMedia::Base64( - BamlMediaType::Audio, - MediaBase64 { - base64: base64, - media_type: format!("audio/{}", mime_type), - }, - )) - }) - } - _ => Ok(part.clone()), - } - }) - .collect::<Vec<_>>(); - async move { - let new_parts = futures::stream::iter(new_parts) - .then(|f| f) - .collect::<Vec<_>>() - .await; - - let new_parts = new_parts.into_iter().collect::<Result<Vec<_>, _>>()?; - - Ok::<_, anyhow::Error>(RenderedChatMessage { - role: p.role.clone(), - parts: new_parts, - }) - } - })) - .then(|f| f) - .collect::<Vec<_>>() - .await - .into_iter() - .collect::<Result<Vec<_>, _>>(); - - let messages = match messages_result { - Ok(messages) => messages, - Err(e) => { - return Err(LLMResponse::OtherFailure(format!("Error occurred: {}", e))); - } - }; - return Ok(messages); + return process_media_urls(ctx, chat) + .await + .map_err(|e| LLMResponse::OtherFailure(format!("Error occurred: {}", e))); } } @@ -410,28 +216,37 @@ where stream: bool, ) -> Result<String> { let rendered_prompt = RenderedPrompt::Chat(prompt.clone()); - + let chat_messages = self.curl_call(ctx, &rendered_prompt).await?; let request_builder = self - .build_request(either::Right(&chat_messages),false, stream) + .build_request(either::Right(&chat_messages), false, stream) .await?; - let request: reqwest::Request = request_builder.build()?; + let mut request = request_builder.build()?; let url_header_value = { - - let url_header_value = request.url(); + let headers = request.headers_mut(); + let url_header_value = headers + .get("baml-render-url") + .ok_or(anyhow::anyhow!("Missing header 'baml-render-url'"))?; url_header_value.to_owned() }; let url_str = url_header_value - .to_string(); - - + .to_str() + .map_err(|_| anyhow::anyhow!("Invalid header 'baml-render-url'"))?; + let new_url = Url::from_str(url_str)?; + *request.url_mut() = new_url; + + { + let headers = request.headers_mut(); + headers.remove("baml-original-url"); + headers.remove("baml-render-url"); + } let body = request .body() .map(|b| b.as_bytes().unwrap_or_default().to_vec()) .unwrap_or_default(); // Add this line to handle the Option - let request_str = to_curl_command(url_str.as_str(), "POST", request.headers(), body); + let request_str = to_curl_command(url_str, "POST", request.headers(), body); Ok(request_str) } @@ -469,107 +284,12 @@ where async fn stream(&self, ctx: &RuntimeContext, prompt: &RenderedPrompt) -> StreamResponse { if self.model_features().resolve_media_urls { if let RenderedPrompt::Chat(ref chat) = prompt { - let messages = futures::stream::iter(chat.iter().map(|p| { - let new_parts = p - .parts - .iter() - .map(|part| async move { - match part { - ChatMessagePart::Image(BamlMedia::Url(_, media_url)) - | ChatMessagePart::Audio(BamlMedia::Url(_, media_url)) => { - let mut base64 = "".to_string(); - let mut mime_type = "".to_string(); - if media_url.url.starts_with("data:") { - let parts: Vec<&str> = - media_url.url.splitn(2, ',').collect(); - base64 = parts.get(1).unwrap().to_string(); - let prefix = parts.get(0).unwrap(); - mime_type = prefix - .splitn(2, ':') - .last() - .unwrap() // Get the part after "data:" - .split('/') - .last() - .unwrap() // Get the part after "image/" - .split(';') - .next() - .unwrap() // Get the part before ";base64" - .to_string(); - } else { - let client = reqwest::Client::new(); - let response = match client - .get(&media_url.url) - // NB(sam): this would workaround CORS issues, but https://github.com/seanmonstar/reqwest/issues/1401 - //.fetch_mode_no_cors() - .send() - .await - { - Ok(response) => response, - Err(e) => { - return Err(LLMResponse::OtherFailure( - "Failed to fetch image due to CORS issue" - .to_string(), - )) - } // replace with your error conversion logic - }; - let bytes = match response.bytes().await { - Ok(bytes) => bytes, - Err(e) => { - return Err(LLMResponse::OtherFailure( - e.to_string(), - )) - } // replace with your error conversion logic - }; - base64 = BASE64_STANDARD.encode(&bytes); - let inferred_type = infer::get(&bytes); - mime_type = inferred_type.map_or_else( - || "application/octet-stream".into(), - |t| t.extension().into(), - ); - } - Ok(if matches!(part, ChatMessagePart::Image(_)) { - ChatMessagePart::Image(BamlMedia::Base64( - BamlMediaType::Image, - MediaBase64 { - base64: base64, - media_type: format!("image/{}", mime_type), - }, - )) - } else { - ChatMessagePart::Audio(BamlMedia::Base64( - BamlMediaType::Audio, - MediaBase64 { - base64: base64, - media_type: format!("audio/{}", mime_type), - }, - )) - }) - } - _ => Ok(part.clone()), - } - }) - .collect::<Vec<_>>(); - async move { - let new_parts = futures::stream::iter(new_parts) - .then(|f| f) - .collect::<Vec<_>>() - .await; - - let new_parts = new_parts.into_iter().collect::<Result<Vec<_>, _>>()?; - - Ok(RenderedChatMessage { - role: p.role.clone(), - parts: new_parts, - }) + match process_media_urls(ctx, chat).await { + Ok(messages) => return self.stream_chat(ctx, &messages).await, + Err(e) => { + return Err(LLMResponse::OtherFailure(format!("Error occurred: {}", e))) } - })) - .then(|f| f) - .collect::<Vec<_>>() - .await - .into_iter() - .collect::<Result<Vec<_>, _>>()?; - - return self.stream_chat(ctx, &messages).await; + } } } @@ -579,3 +299,122 @@ where } } } + +async fn process_media_urls( + ctx: &RuntimeContext, + chat: &Vec<RenderedChatMessage>, +) -> Result<Vec<RenderedChatMessage>, anyhow::Error> { + let messages_result = futures::stream::iter(chat.iter().map(|p| { + let new_parts = p + .parts + .iter() + .map(|part| async move { + match part { + ChatMessagePart::Image(BamlMedia::Url(_, media_url)) + | ChatMessagePart::Audio(BamlMedia::Url(_, media_url)) => { + let (base64, mime_type) = if media_url.url.starts_with("data:") { + let parts: Vec<&str> = media_url.url.splitn(2, ',').collect(); + let base64 = parts.get(1).unwrap().to_string(); + let prefix = parts.get(0).unwrap(); + let mime_type = prefix + .splitn(2, ':') + .next() + .unwrap() + .to_string() + .split('/') + .last() + .unwrap() + .to_string(); + + (base64, mime_type) + } else { + let response = match fetch_with_proxy( + &media_url.url, + ctx.env + .get("BOUNDARY_PROXY_URL") + .as_deref() + .map(|s| s.as_str()), + ) + .await + { + Ok(response) => response, + Err(e) => { + return Err(anyhow::anyhow!("Failed to fetch media: {e:?}")) + } + }; + let bytes = match response.bytes().await { + Ok(bytes) => bytes, + Err(e) => { + return Err(anyhow::anyhow!( + "Failed to fetch media bytes: {e:?}" + )) + } + }; + let base64 = BASE64_STANDARD.encode(&bytes); + let inferred_type = infer::get(&bytes); + let mime_type = inferred_type.map_or_else( + || "application/octet-stream".into(), + |t| t.extension().into(), + ); + (base64, mime_type) + }; + + Ok(if matches!(part, ChatMessagePart::Image(_)) { + ChatMessagePart::Image(BamlMedia::Base64( + BamlMediaType::Image, + MediaBase64 { + base64: base64, + media_type: format!("image/{}", mime_type), + }, + )) + } else { + ChatMessagePart::Audio(BamlMedia::Base64( + BamlMediaType::Audio, + MediaBase64 { + base64: base64, + media_type: format!("audio/{}", mime_type), + }, + )) + }) + } + _ => Ok(part.clone()), + } + }) + .collect::<Vec<_>>(); + async move { + let new_parts = futures::stream::iter(new_parts) + .then(|f| f) + .collect::<Vec<_>>() + .await; + + let new_parts = new_parts.into_iter().collect::<Result<Vec<_>, _>>()?; + + Ok::<_, anyhow::Error>(RenderedChatMessage { + role: p.role.clone(), + parts: new_parts, + }) + } + })) + .then(|f| f) + .collect::<Vec<_>>() + .await + .into_iter() + .collect::<Result<Vec<_>, _>>(); + + messages_result +} + +async fn fetch_with_proxy( + url: &str, + proxy_url: Option<&str>, +) -> Result<reqwest::Response, anyhow::Error> { + let client = reqwest::Client::new(); + let mut request = if let Some(proxy) = proxy_url { + client.get(proxy).header("baml-original-url", url) + } else { + client.get(url) + }; + + let response = request.send().await?; + Ok(response) +} diff --git a/integ-tests/baml_src/test-files/functions/input/named-args/single/named-image.baml b/integ-tests/baml_src/test-files/functions/input/named-args/single/named-image.baml index 65770d14c..cf06975c3 100644 --- a/integ-tests/baml_src/test-files/functions/input/named-args/single/named-image.baml +++ b/integ-tests/baml_src/test-files/functions/input/named-args/single/named-image.baml @@ -1,5 +1,5 @@ function TestImageInput(img: image) -> string{ - client AwsBedrock + client Gemini prompt #" {{ _.role("user") }} diff --git a/integ-tests/python/baml_client/inlinedbaml.py b/integ-tests/python/baml_client/inlinedbaml.py index 58600252c..76b671d4b 100644 --- a/integ-tests/python/baml_client/inlinedbaml.py +++ b/integ-tests/python/baml_client/inlinedbaml.py @@ -36,7 +36,7 @@ "test-files/functions/input/named-args/single/named-enum-list.baml": "enum NamedArgsSingleEnumList {\n ONE\n TWO\n}\n\nfunction TestFnNamedArgsSingleEnumList(myArg: NamedArgsSingleEnumList[]) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest TestFnNamedArgsSingleEnumList {\n functions [TestFnNamedArgsSingleEnumList]\n args {\n myArg [ONE, TWO]\n }\n}", "test-files/functions/input/named-args/single/named-enum.baml": "enum NamedArgsSingleEnum {\n ONE\n TWO\n}\n\nfunction FnTestNamedArgsSingleEnum(myArg: NamedArgsSingleEnum) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest FnTestNamedArgsSingleEnum {\n functions [FnTestNamedArgsSingleEnum]\n args {\n myArg ONE\n }\n}", "test-files/functions/input/named-args/single/named-float.baml": "function TestFnNamedArgsSingleFloat(myFloat: float) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myFloat}}\n \"#\n}\n\ntest TestFnNamedArgsSingleFloat {\n functions [TestFnNamedArgsSingleFloat]\n args {\n myFloat 3.14\n }\n}\n", - "test-files/functions/input/named-args/single/named-image.baml": "function TestImageInput(img: image) -> string{\n client AwsBedrock\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", + "test-files/functions/input/named-args/single/named-image.baml": "function TestImageInput(img: image) -> string{\n client Gemini\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", "test-files/functions/input/named-args/single/named-int.baml": "// test for int\nfunction TestFnNamedArgsSingleInt(myInt: int) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myInt}}\n \"#\n}\n\ntest TestFnNamedArgsSingleInt {\n functions [TestFnNamedArgsSingleInt]\n args {\n myInt 42\n }\n}\n", "test-files/functions/input/named-args/single/named-string-list.baml": "// string[]\nfunction TestFnNamedArgsSingleStringArray(myStringArray: string[]) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myStringArray}}\n \"#\n}\n\ntest TestFnNamedArgsSingleStringArray {\n functions [TestFnNamedArgsSingleStringArray]\n args {\n myStringArray [\"example1\", \"example2\", \"example3\"]\n }\n}\n", "test-files/functions/input/named-args/single/named-string-optional.baml": "\n\n // string[]\nfunction FnNamedArgsSingleStringOptional(myString: string?) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myString}}\n \"#\n}\n\ntest FnNamedArgsSingleStringOptional {\n functions [FnNamedArgsSingleStringOptional]\n args {\n myString \"example string\"\n }\n}\n\ntest FnNamedArgsSingleStringOptional2 {\n functions [FnNamedArgsSingleStringOptional]\n args {\n \n }\n}\n", diff --git a/integ-tests/ruby/baml_client/inlined.rb b/integ-tests/ruby/baml_client/inlined.rb index cbbe279b5..b6086cfb6 100644 --- a/integ-tests/ruby/baml_client/inlined.rb +++ b/integ-tests/ruby/baml_client/inlined.rb @@ -36,7 +36,7 @@ module Inlined "test-files/functions/input/named-args/single/named-enum-list.baml" => "enum NamedArgsSingleEnumList {\n ONE\n TWO\n}\n\nfunction TestFnNamedArgsSingleEnumList(myArg: NamedArgsSingleEnumList[]) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest TestFnNamedArgsSingleEnumList {\n functions [TestFnNamedArgsSingleEnumList]\n args {\n myArg [ONE, TWO]\n }\n}", "test-files/functions/input/named-args/single/named-enum.baml" => "enum NamedArgsSingleEnum {\n ONE\n TWO\n}\n\nfunction FnTestNamedArgsSingleEnum(myArg: NamedArgsSingleEnum) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest FnTestNamedArgsSingleEnum {\n functions [FnTestNamedArgsSingleEnum]\n args {\n myArg ONE\n }\n}", "test-files/functions/input/named-args/single/named-float.baml" => "function TestFnNamedArgsSingleFloat(myFloat: float) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myFloat}}\n \"#\n}\n\ntest TestFnNamedArgsSingleFloat {\n functions [TestFnNamedArgsSingleFloat]\n args {\n myFloat 3.14\n }\n}\n", - "test-files/functions/input/named-args/single/named-image.baml" => "function TestImageInput(img: image) -> string{\n client AwsBedrock\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", + "test-files/functions/input/named-args/single/named-image.baml" => "function TestImageInput(img: image) -> string{\n client Gemini\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", "test-files/functions/input/named-args/single/named-int.baml" => "// test for int\nfunction TestFnNamedArgsSingleInt(myInt: int) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myInt}}\n \"#\n}\n\ntest TestFnNamedArgsSingleInt {\n functions [TestFnNamedArgsSingleInt]\n args {\n myInt 42\n }\n}\n", "test-files/functions/input/named-args/single/named-string-list.baml" => "// string[]\nfunction TestFnNamedArgsSingleStringArray(myStringArray: string[]) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myStringArray}}\n \"#\n}\n\ntest TestFnNamedArgsSingleStringArray {\n functions [TestFnNamedArgsSingleStringArray]\n args {\n myStringArray [\"example1\", \"example2\", \"example3\"]\n }\n}\n", "test-files/functions/input/named-args/single/named-string-optional.baml" => "\n\n // string[]\nfunction FnNamedArgsSingleStringOptional(myString: string?) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myString}}\n \"#\n}\n\ntest FnNamedArgsSingleStringOptional {\n functions [FnNamedArgsSingleStringOptional]\n args {\n myString \"example string\"\n }\n}\n\ntest FnNamedArgsSingleStringOptional2 {\n functions [FnNamedArgsSingleStringOptional]\n args {\n \n }\n}\n", diff --git a/integ-tests/typescript/baml_client/inlinedbaml.ts b/integ-tests/typescript/baml_client/inlinedbaml.ts index 32d9fb6da..d98b8c24e 100644 --- a/integ-tests/typescript/baml_client/inlinedbaml.ts +++ b/integ-tests/typescript/baml_client/inlinedbaml.ts @@ -37,7 +37,7 @@ const fileMap = { "test-files/functions/input/named-args/single/named-enum-list.baml": "enum NamedArgsSingleEnumList {\n ONE\n TWO\n}\n\nfunction TestFnNamedArgsSingleEnumList(myArg: NamedArgsSingleEnumList[]) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest TestFnNamedArgsSingleEnumList {\n functions [TestFnNamedArgsSingleEnumList]\n args {\n myArg [ONE, TWO]\n }\n}", "test-files/functions/input/named-args/single/named-enum.baml": "enum NamedArgsSingleEnum {\n ONE\n TWO\n}\n\nfunction FnTestNamedArgsSingleEnum(myArg: NamedArgsSingleEnum) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest FnTestNamedArgsSingleEnum {\n functions [FnTestNamedArgsSingleEnum]\n args {\n myArg ONE\n }\n}", "test-files/functions/input/named-args/single/named-float.baml": "function TestFnNamedArgsSingleFloat(myFloat: float) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myFloat}}\n \"#\n}\n\ntest TestFnNamedArgsSingleFloat {\n functions [TestFnNamedArgsSingleFloat]\n args {\n myFloat 3.14\n }\n}\n", - "test-files/functions/input/named-args/single/named-image.baml": "function TestImageInput(img: image) -> string{\n client AwsBedrock\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", + "test-files/functions/input/named-args/single/named-image.baml": "function TestImageInput(img: image) -> string{\n client Gemini\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", "test-files/functions/input/named-args/single/named-int.baml": "// test for int\nfunction TestFnNamedArgsSingleInt(myInt: int) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myInt}}\n \"#\n}\n\ntest TestFnNamedArgsSingleInt {\n functions [TestFnNamedArgsSingleInt]\n args {\n myInt 42\n }\n}\n", "test-files/functions/input/named-args/single/named-string-list.baml": "// string[]\nfunction TestFnNamedArgsSingleStringArray(myStringArray: string[]) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myStringArray}}\n \"#\n}\n\ntest TestFnNamedArgsSingleStringArray {\n functions [TestFnNamedArgsSingleStringArray]\n args {\n myStringArray [\"example1\", \"example2\", \"example3\"]\n }\n}\n", "test-files/functions/input/named-args/single/named-string-optional.baml": "\n\n // string[]\nfunction FnNamedArgsSingleStringOptional(myString: string?) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myString}}\n \"#\n}\n\ntest FnNamedArgsSingleStringOptional {\n functions [FnNamedArgsSingleStringOptional]\n args {\n myString \"example string\"\n }\n}\n\ntest FnNamedArgsSingleStringOptional2 {\n functions [FnNamedArgsSingleStringOptional]\n args {\n \n }\n}\n", From 58ff0b62cceadff862f6b293eaaef66774ceea67 Mon Sep 17 00:00:00 2001 From: Anish Palakurthi <anish.palakurthi@gmail.com> Date: Mon, 8 Jul 2024 15:36:44 -0700 Subject: [PATCH 11/11] reverted integ test --- .../src/internal/llm_client/traits/mod.rs | 14 +++----------- .../input/named-args/single/named-image.baml | 2 +- integ-tests/python/baml_client/inlinedbaml.py | 2 +- integ-tests/ruby/baml_client/inlined.rb | 2 +- integ-tests/typescript/baml_client/inlinedbaml.ts | 2 +- 5 files changed, 7 insertions(+), 15 deletions(-) diff --git a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs index 40e3bc926..d652f5c53 100644 --- a/engine/baml-runtime/src/internal/llm_client/traits/mod.rs +++ b/engine/baml-runtime/src/internal/llm_client/traits/mod.rs @@ -223,30 +223,22 @@ where .await?; let mut request = request_builder.build()?; let url_header_value = { - let headers = request.headers_mut(); - let url_header_value = headers - .get("baml-render-url") - .ok_or(anyhow::anyhow!("Missing header 'baml-render-url'"))?; + let url_header_value = request.url(); url_header_value.to_owned() }; - let url_str = url_header_value - .to_str() - .map_err(|_| anyhow::anyhow!("Invalid header 'baml-render-url'"))?; - let new_url = Url::from_str(url_str)?; - *request.url_mut() = new_url; + let url_str = url_header_value.to_string(); { let headers = request.headers_mut(); headers.remove("baml-original-url"); - headers.remove("baml-render-url"); } let body = request .body() .map(|b| b.as_bytes().unwrap_or_default().to_vec()) .unwrap_or_default(); // Add this line to handle the Option - let request_str = to_curl_command(url_str, "POST", request.headers(), body); + let request_str = to_curl_command(&url_str, "POST", request.headers(), body); Ok(request_str) } diff --git a/integ-tests/baml_src/test-files/functions/input/named-args/single/named-image.baml b/integ-tests/baml_src/test-files/functions/input/named-args/single/named-image.baml index cf06975c3..65770d14c 100644 --- a/integ-tests/baml_src/test-files/functions/input/named-args/single/named-image.baml +++ b/integ-tests/baml_src/test-files/functions/input/named-args/single/named-image.baml @@ -1,5 +1,5 @@ function TestImageInput(img: image) -> string{ - client Gemini + client AwsBedrock prompt #" {{ _.role("user") }} diff --git a/integ-tests/python/baml_client/inlinedbaml.py b/integ-tests/python/baml_client/inlinedbaml.py index 76b671d4b..58600252c 100644 --- a/integ-tests/python/baml_client/inlinedbaml.py +++ b/integ-tests/python/baml_client/inlinedbaml.py @@ -36,7 +36,7 @@ "test-files/functions/input/named-args/single/named-enum-list.baml": "enum NamedArgsSingleEnumList {\n ONE\n TWO\n}\n\nfunction TestFnNamedArgsSingleEnumList(myArg: NamedArgsSingleEnumList[]) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest TestFnNamedArgsSingleEnumList {\n functions [TestFnNamedArgsSingleEnumList]\n args {\n myArg [ONE, TWO]\n }\n}", "test-files/functions/input/named-args/single/named-enum.baml": "enum NamedArgsSingleEnum {\n ONE\n TWO\n}\n\nfunction FnTestNamedArgsSingleEnum(myArg: NamedArgsSingleEnum) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest FnTestNamedArgsSingleEnum {\n functions [FnTestNamedArgsSingleEnum]\n args {\n myArg ONE\n }\n}", "test-files/functions/input/named-args/single/named-float.baml": "function TestFnNamedArgsSingleFloat(myFloat: float) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myFloat}}\n \"#\n}\n\ntest TestFnNamedArgsSingleFloat {\n functions [TestFnNamedArgsSingleFloat]\n args {\n myFloat 3.14\n }\n}\n", - "test-files/functions/input/named-args/single/named-image.baml": "function TestImageInput(img: image) -> string{\n client Gemini\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", + "test-files/functions/input/named-args/single/named-image.baml": "function TestImageInput(img: image) -> string{\n client AwsBedrock\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", "test-files/functions/input/named-args/single/named-int.baml": "// test for int\nfunction TestFnNamedArgsSingleInt(myInt: int) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myInt}}\n \"#\n}\n\ntest TestFnNamedArgsSingleInt {\n functions [TestFnNamedArgsSingleInt]\n args {\n myInt 42\n }\n}\n", "test-files/functions/input/named-args/single/named-string-list.baml": "// string[]\nfunction TestFnNamedArgsSingleStringArray(myStringArray: string[]) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myStringArray}}\n \"#\n}\n\ntest TestFnNamedArgsSingleStringArray {\n functions [TestFnNamedArgsSingleStringArray]\n args {\n myStringArray [\"example1\", \"example2\", \"example3\"]\n }\n}\n", "test-files/functions/input/named-args/single/named-string-optional.baml": "\n\n // string[]\nfunction FnNamedArgsSingleStringOptional(myString: string?) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myString}}\n \"#\n}\n\ntest FnNamedArgsSingleStringOptional {\n functions [FnNamedArgsSingleStringOptional]\n args {\n myString \"example string\"\n }\n}\n\ntest FnNamedArgsSingleStringOptional2 {\n functions [FnNamedArgsSingleStringOptional]\n args {\n \n }\n}\n", diff --git a/integ-tests/ruby/baml_client/inlined.rb b/integ-tests/ruby/baml_client/inlined.rb index b6086cfb6..cbbe279b5 100644 --- a/integ-tests/ruby/baml_client/inlined.rb +++ b/integ-tests/ruby/baml_client/inlined.rb @@ -36,7 +36,7 @@ module Inlined "test-files/functions/input/named-args/single/named-enum-list.baml" => "enum NamedArgsSingleEnumList {\n ONE\n TWO\n}\n\nfunction TestFnNamedArgsSingleEnumList(myArg: NamedArgsSingleEnumList[]) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest TestFnNamedArgsSingleEnumList {\n functions [TestFnNamedArgsSingleEnumList]\n args {\n myArg [ONE, TWO]\n }\n}", "test-files/functions/input/named-args/single/named-enum.baml" => "enum NamedArgsSingleEnum {\n ONE\n TWO\n}\n\nfunction FnTestNamedArgsSingleEnum(myArg: NamedArgsSingleEnum) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest FnTestNamedArgsSingleEnum {\n functions [FnTestNamedArgsSingleEnum]\n args {\n myArg ONE\n }\n}", "test-files/functions/input/named-args/single/named-float.baml" => "function TestFnNamedArgsSingleFloat(myFloat: float) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myFloat}}\n \"#\n}\n\ntest TestFnNamedArgsSingleFloat {\n functions [TestFnNamedArgsSingleFloat]\n args {\n myFloat 3.14\n }\n}\n", - "test-files/functions/input/named-args/single/named-image.baml" => "function TestImageInput(img: image) -> string{\n client Gemini\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", + "test-files/functions/input/named-args/single/named-image.baml" => "function TestImageInput(img: image) -> string{\n client AwsBedrock\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", "test-files/functions/input/named-args/single/named-int.baml" => "// test for int\nfunction TestFnNamedArgsSingleInt(myInt: int) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myInt}}\n \"#\n}\n\ntest TestFnNamedArgsSingleInt {\n functions [TestFnNamedArgsSingleInt]\n args {\n myInt 42\n }\n}\n", "test-files/functions/input/named-args/single/named-string-list.baml" => "// string[]\nfunction TestFnNamedArgsSingleStringArray(myStringArray: string[]) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myStringArray}}\n \"#\n}\n\ntest TestFnNamedArgsSingleStringArray {\n functions [TestFnNamedArgsSingleStringArray]\n args {\n myStringArray [\"example1\", \"example2\", \"example3\"]\n }\n}\n", "test-files/functions/input/named-args/single/named-string-optional.baml" => "\n\n // string[]\nfunction FnNamedArgsSingleStringOptional(myString: string?) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myString}}\n \"#\n}\n\ntest FnNamedArgsSingleStringOptional {\n functions [FnNamedArgsSingleStringOptional]\n args {\n myString \"example string\"\n }\n}\n\ntest FnNamedArgsSingleStringOptional2 {\n functions [FnNamedArgsSingleStringOptional]\n args {\n \n }\n}\n", diff --git a/integ-tests/typescript/baml_client/inlinedbaml.ts b/integ-tests/typescript/baml_client/inlinedbaml.ts index d98b8c24e..32d9fb6da 100644 --- a/integ-tests/typescript/baml_client/inlinedbaml.ts +++ b/integ-tests/typescript/baml_client/inlinedbaml.ts @@ -37,7 +37,7 @@ const fileMap = { "test-files/functions/input/named-args/single/named-enum-list.baml": "enum NamedArgsSingleEnumList {\n ONE\n TWO\n}\n\nfunction TestFnNamedArgsSingleEnumList(myArg: NamedArgsSingleEnumList[]) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest TestFnNamedArgsSingleEnumList {\n functions [TestFnNamedArgsSingleEnumList]\n args {\n myArg [ONE, TWO]\n }\n}", "test-files/functions/input/named-args/single/named-enum.baml": "enum NamedArgsSingleEnum {\n ONE\n TWO\n}\n\nfunction FnTestNamedArgsSingleEnum(myArg: NamedArgsSingleEnum) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest FnTestNamedArgsSingleEnum {\n functions [FnTestNamedArgsSingleEnum]\n args {\n myArg ONE\n }\n}", "test-files/functions/input/named-args/single/named-float.baml": "function TestFnNamedArgsSingleFloat(myFloat: float) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myFloat}}\n \"#\n}\n\ntest TestFnNamedArgsSingleFloat {\n functions [TestFnNamedArgsSingleFloat]\n args {\n myFloat 3.14\n }\n}\n", - "test-files/functions/input/named-args/single/named-image.baml": "function TestImageInput(img: image) -> string{\n client Gemini\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", + "test-files/functions/input/named-args/single/named-image.baml": "function TestImageInput(img: image) -> string{\n client AwsBedrock\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", "test-files/functions/input/named-args/single/named-int.baml": "// test for int\nfunction TestFnNamedArgsSingleInt(myInt: int) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myInt}}\n \"#\n}\n\ntest TestFnNamedArgsSingleInt {\n functions [TestFnNamedArgsSingleInt]\n args {\n myInt 42\n }\n}\n", "test-files/functions/input/named-args/single/named-string-list.baml": "// string[]\nfunction TestFnNamedArgsSingleStringArray(myStringArray: string[]) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myStringArray}}\n \"#\n}\n\ntest TestFnNamedArgsSingleStringArray {\n functions [TestFnNamedArgsSingleStringArray]\n args {\n myStringArray [\"example1\", \"example2\", \"example3\"]\n }\n}\n", "test-files/functions/input/named-args/single/named-string-optional.baml": "\n\n // string[]\nfunction FnNamedArgsSingleStringOptional(myString: string?) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myString}}\n \"#\n}\n\ntest FnNamedArgsSingleStringOptional {\n functions [FnNamedArgsSingleStringOptional]\n args {\n myString \"example string\"\n }\n}\n\ntest FnNamedArgsSingleStringOptional2 {\n functions [FnNamedArgsSingleStringOptional]\n args {\n \n }\n}\n",