-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for arbritrary metadata (e.g. cache_policy for anthropic) (…
…#893) Add ability for people to support caching or any future content metadata that someone may wish to add. Most LLM apis have converged on: ``` { role: string content: { ... // multiple variants }[] } ``` We now allow for people to inject arbitrary metadata into the properties of content (or appropriately named field for any llm api all. What is not yet supported: * indexing and adding metadata to subinterfaces of content (i.e. setting content.image_type.detail) * adding metadata as a sibling to role, content The playground and raw_curl correctly display this so if a provider doesn't support a speicfic metadat, we do support it. Complete e2e example: ```rust client<llm> Foo { provider openai options { allowed_role_metadata: ["foo", "bar"] } } client<llm> FooWithout { provider openai options { } } template_string Foo() #" {{ _.role('user', foo={"type": "ephemeral"}, bar="1", cat=True) }} This will be have foo and bar, but not cat metadata. But only for Foo, not FooWithout. {{ _.role('user') }} This will have none of the role metadata for Foo or FooWithout. "# ``` Metadata included: <img width="446" alt="Screenshot 2024-08-23 at 7 41 40 AM" src="https://github.com/user-attachments/assets/e26b1e2d-0377-42af-8629-8fcdff0db3cf"> Metadata excluded: <img width="459" alt="Screenshot 2024-08-23 at 7 42 15 AM" src="https://github.com/user-attachments/assets/1dc8fcf3-9a17-4e8d-8a00-29d9bfee31e0"> Potentially breaking changes: * We now merge sequentially matching roles together into the same chunk. ``` [{ "role": "user", "chunk": [A, B] }, { "role": "user", "chunk": [C, D] }] ``` is now converted to ``` [{ "role": "user", "chunk": [A, B, C, D] }] ```
- Loading branch information
Showing
38 changed files
with
8,234 additions
and
9,302 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<ParamField | ||
path="allowed_role_metadata" | ||
type="string[]" | ||
> | ||
Which role metadata should we forward to the API? **Default: `[]`** | ||
|
||
For example you can set this to `["foo", "bar"]` to forward the cache policy to the API. | ||
|
||
If you do not set `allowed_role_metadata`, we will not forward any role metadata to the API even if it is set in the prompt. | ||
|
||
Then in your prompt you can use something like: | ||
```baml | ||
client<llm> Foo { | ||
provider openai | ||
options { | ||
allowed_role_metadata: ["foo", "bar"] | ||
} | ||
} | ||
client<llm> FooWithout { | ||
provider openai | ||
options { | ||
} | ||
} | ||
template_string Foo() #" | ||
{{ _.role('user', foo={"type": "ephemeral"}, bar="1", cat=True) }} | ||
This will be have foo and bar, but not cat metadata. But only for Foo, not FooWithout. | ||
{{ _.role('user') }} | ||
This will have none of the role metadata for Foo or FooWithout. | ||
"# | ||
``` | ||
|
||
You can use the playground to see the raw curl request to see what is being sent to the API. | ||
</ParamField> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<ParamField | ||
path="allowed_role_metadata" | ||
type="string[]" | ||
> | ||
Which role metadata should we forward to the API? **Default: `[]`** | ||
|
||
For example you can set this to `["cache_control"]` to forward the cache policy to the API. | ||
|
||
If you do not set `allowed_role_metadata`, we will not forward any role metadata to the API even if it is set in the prompt. | ||
|
||
Then in your prompt you can use something like: | ||
```baml | ||
client<llm> Foo { | ||
provider anthropic | ||
options { | ||
allowed_role_metadata: ["cache_control"] | ||
} | ||
} | ||
client<llm> FooWithout { | ||
provider anthropic | ||
options { | ||
} | ||
} | ||
template_string Foo() #" | ||
{{ _.role('user', cache_control={"type": "ephemeral"}) }} | ||
This will be cached for Foo, but not for FooWithout! | ||
{{ _.role('user') }} | ||
This will not be cached for Foo or FooWithout! | ||
"# | ||
``` | ||
|
||
You can use the playground to see the raw curl request to see what is being sent to the API. | ||
</ParamField> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
use std::collections::{HashMap, HashSet}; | ||
|
||
use baml_types::{BamlMedia, BamlMediaContent}; | ||
use serde::Serialize; | ||
|
||
use crate::RenderedChatMessage; | ||
|
||
#[derive(Debug, PartialEq, Serialize, Clone)] | ||
pub enum ChatMessagePart { | ||
// raw user-provided text | ||
Text(String), | ||
Media(BamlMedia), | ||
WithMeta(Box<ChatMessagePart>, HashMap<String, serde_json::Value>), | ||
} | ||
|
||
impl ChatMessagePart { | ||
pub fn with_meta(self, meta: HashMap<String, serde_json::Value>) -> ChatMessagePart { | ||
match self { | ||
ChatMessagePart::WithMeta(part, mut existing_meta) => { | ||
existing_meta.extend(meta); | ||
ChatMessagePart::WithMeta(part, existing_meta) | ||
} | ||
_ => ChatMessagePart::WithMeta(Box::new(self), meta), | ||
} | ||
} | ||
|
||
pub fn as_text(&self) -> Option<&String> { | ||
match self { | ||
ChatMessagePart::Text(t) => Some(t), | ||
ChatMessagePart::WithMeta(t, _) => t.as_text(), | ||
ChatMessagePart::Media(_) => None, | ||
} | ||
} | ||
|
||
pub fn as_media(&self) -> Option<&BamlMedia> { | ||
match self { | ||
ChatMessagePart::Media(m) => Some(m), | ||
ChatMessagePart::WithMeta(t, _) => t.as_media(), | ||
ChatMessagePart::Text(_) => None, | ||
} | ||
} | ||
|
||
pub fn meta(&self) -> Option<&HashMap<String, serde_json::Value>> { | ||
match self { | ||
ChatMessagePart::WithMeta(_, meta) => Some(meta), | ||
_ => None, | ||
} | ||
} | ||
|
||
pub fn as_completion(self) -> String { | ||
match self { | ||
ChatMessagePart::Text(t) => t, | ||
ChatMessagePart::Media(_) => "".to_string(), // we are choosing to ignore the image for now | ||
ChatMessagePart::WithMeta(p, _) => p.as_completion(), | ||
} | ||
} | ||
} | ||
|
||
impl std::fmt::Display for ChatMessagePart { | ||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
match self { | ||
ChatMessagePart::Text(t) => write!(f, "{}", t), | ||
ChatMessagePart::Media(media) => match &media.content { | ||
BamlMediaContent::Url(url) => { | ||
write!(f, "<{}_placeholder: {}>", media.media_type, url.url) | ||
} | ||
BamlMediaContent::Base64(_) => { | ||
write!(f, "<{}_placeholder base64>", media.media_type) | ||
} | ||
BamlMediaContent::File(file) => write!( | ||
f, | ||
"<{}_placeholder: {}>", | ||
media.media_type, | ||
file.relpath.to_string_lossy() | ||
), | ||
}, | ||
ChatMessagePart::WithMeta(part, meta) => write!(f, "{:?}::{}", meta, part), | ||
} | ||
} | ||
} |
Oops, something went wrong.