Skip to content

Commit 67b3f4f

Browse files
Fetch API (#1916)
<!-- ELLIPSIS_HIDDEN --> > [!IMPORTANT] > Introduces `fetch_value` built-in function for HTTP GET requests in BAML, with parsing, type checking, and evaluation support. > > - **Behavior**: > - Adds `fetch_value` built-in function in `baml-core/src/ir/builtin.rs` to perform HTTP GET requests. > - Parses response into specified type using `jsonish` library. > - Supports only GET method with `base_url`, `headers`, and `query_params`. > - **Parsing**: > - Updates `parse_expr.rs` and `parse_expression.rs` to handle generic function applications. > - Adds `App` struct in `ast/app.rs` to represent function applications with type arguments. > - **Type Checking**: > - Modifies `expr_typecheck.rs` to include type checking for `fetch_value`. > - Ensures type arguments are provided for generic functions. > - **Evaluation**: > - Implements evaluation logic in `eval_expr.rs` to execute HTTP requests and parse responses. > - Handles proxy URL and API key injection in `fiddle-proxy/server.js`. > - **Testing**: > - Adds tests in `validation_files/expr/builtin.baml` and `constructors_invalid.baml` to validate new functionality. > - **Misc**: > - Updates `field_type/mod.rs` and `field_type/builder.rs` to support new types and methods. > > <sup>This description was created by </sup>[<img alt="Ellipsis" src="https://img.shields.io/badge/Ellipsis-blue?color=175173">](https://www.ellipsis.dev?ref=BoundaryML%2Fbaml&utm_source=github&utm_medium=referral)<sup> for 4f15177. You can [customize](https://app.ellipsis.dev/BoundaryML/settings/summaries) this summary. It will automatically update as commits are pushed.</sup> <!-- ELLIPSIS_HIDDEN --> --------- Co-authored-by: Greg Hale <imalsogreg@gmail.com>
1 parent 0363df7 commit 67b3f4f

45 files changed

Lines changed: 1329 additions & 385 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
use super::repr::{Class, Enum, EnumValue, ExprFunction, Field, Node, NodeAttributes};
2+
use crate::{ir::repr::IntermediateRepr, Configuration};
3+
use baml_types::{
4+
expr::{Builtin, Expr, ExprMetadata},
5+
Arrow, FieldType,
6+
};
7+
use internal_baml_diagnostics::Span;
8+
9+
pub mod functions {
10+
pub const FETCH_VALUE: &str = "std::fetch_value";
11+
}
12+
13+
pub mod classes {
14+
pub const REQUEST: &str = "std::Request";
15+
}
16+
17+
pub mod enums {
18+
pub const HTTP_METHOD: &str = "std::HttpMethod";
19+
}
20+
21+
/// Builtins are exposed through a separate IR, which can be combined with
22+
/// the user's IR via `IntermediateRepr::extend`.
23+
pub fn builtin_ir() -> IntermediateRepr {
24+
IntermediateRepr {
25+
enums: builtin_enums(),
26+
classes: builtin_classes(),
27+
type_aliases: vec![],
28+
functions: vec![],
29+
expr_fns: vec![],
30+
toplevel_assignments: vec![],
31+
clients: vec![],
32+
retry_policies: vec![],
33+
template_strings: vec![],
34+
finite_recursive_cycles: vec![],
35+
structural_recursive_alias_cycles: vec![],
36+
configuration: Configuration::default(),
37+
}
38+
}
39+
40+
fn builtin<T, const N: usize>(elems: [T; N]) -> Vec<Node<T>> {
41+
let mut attributes = NodeAttributes::default();
42+
attributes.span = Some(Span::fake());
43+
44+
Vec::from_iter(elems.into_iter().map(|e| Node {
45+
attributes: NodeAttributes::default(),
46+
elem: e,
47+
}))
48+
}
49+
50+
pub fn builtin_classes() -> Vec<Node<Class>> {
51+
builtin([Class {
52+
name: String::from(classes::REQUEST),
53+
docstring: None,
54+
static_fields: vec![
55+
// Node {
56+
// attributes: NodeAttributes::default(),
57+
// elem: Field {
58+
// name: String::from("method"),
59+
// r#type: Node {
60+
// elem: FieldType::r#enum(enums::HTTP_METHOD),
61+
// attributes: NodeAttributes::default(),
62+
// },
63+
// docstring: None,
64+
// },
65+
// },
66+
Node {
67+
attributes: NodeAttributes::default(),
68+
elem: Field {
69+
name: String::from("base_url"),
70+
r#type: Node {
71+
elem: FieldType::string(),
72+
attributes: NodeAttributes::default(),
73+
},
74+
docstring: None,
75+
},
76+
},
77+
Node {
78+
attributes: NodeAttributes::default(),
79+
elem: Field {
80+
name: String::from("headers"),
81+
r#type: Node {
82+
elem: FieldType::map(FieldType::string(), FieldType::string()),
83+
attributes: NodeAttributes::default(),
84+
},
85+
docstring: None,
86+
},
87+
},
88+
Node {
89+
attributes: NodeAttributes::default(),
90+
elem: Field {
91+
name: String::from("query_params"),
92+
r#type: Node {
93+
elem: FieldType::map(FieldType::string(), FieldType::string()),
94+
attributes: NodeAttributes::default(),
95+
},
96+
docstring: None,
97+
},
98+
},
99+
],
100+
inputs: vec![],
101+
}])
102+
}
103+
104+
pub fn builtin_enums() -> Vec<Node<Enum>> {
105+
builtin([Enum {
106+
name: String::from(enums::HTTP_METHOD),
107+
docstring: None,
108+
values: vec![(
109+
Node {
110+
attributes: NodeAttributes::default(),
111+
elem: EnumValue(String::from("Get")),
112+
},
113+
None,
114+
)],
115+
}])
116+
}
117+
118+
/// This builds a specialized version of an std generic function.
119+
///
120+
/// For now we only have functions that take in a generic type parameter and
121+
/// return that same type, generics do not appear in function parameters. So
122+
/// managing this is fairly simple, but will require carrying additional data
123+
/// when actual user defined generics are introduced.
124+
pub fn builtin_generic_fn(f: Builtin, return_type: FieldType) -> Expr<ExprMetadata> {
125+
let signature = match f {
126+
// fn fetch_value<T>(request: std::Request) -> T
127+
Builtin::FetchValue => Arrow {
128+
param_types: vec![FieldType::class(classes::REQUEST)],
129+
return_type,
130+
},
131+
};
132+
133+
Expr::Builtin(f, (Span::fake(), Some(FieldType::arrow(signature))))
134+
}
135+
136+
pub fn is_builtin_identifier(identifier: &str) -> bool {
137+
identifier.starts_with("std::")
138+
}

engine/baml-lib/baml-core/src/ir/ir_helpers/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@ pub trait IRHelperExtended: IRSemanticStreamingHelper {
195195
(FieldType::Tuple(_), _) => false,
196196
(FieldType::Enum(_), _) => false,
197197
(FieldType::Class(_), _) => false,
198-
199198
(FieldType::Arrow(arrow1), FieldType::Arrow(arrow2)) => {
200199
let param_lengths_match = arrow1.param_types.len() == arrow2.param_types.len();
201200
// N.B. Functions are covariant in their return type and contravariant in their arguments.

engine/baml-lib/baml-core/src/ir/json_schema.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ impl WithJsonSchema for FieldType {
204204
schema["default"] = serde_json::Value::Null;
205205
}
206206
schema
207-
},
207+
}
208208
// Handle map types with optional support
209209
// For example: map<string, int>? generates a schema that allows both object and null
210210
FieldType::Map(_k, v) => {
@@ -222,7 +222,7 @@ impl WithJsonSchema for FieldType {
222222
schema["default"] = serde_json::Value::Null;
223223
}
224224
schema
225-
},
225+
}
226226
FieldType::Union(options) => json!({
227227
"anyOf": options.iter().map(|t| {
228228
let mut res = t.json_schema();
@@ -263,7 +263,8 @@ impl WithJsonSchema for FieldType {
263263
}
264264
}
265265
FieldType::WithMetadata { base, .. } => base.json_schema(),
266-
FieldType::Arrow(_) => json!({}), // TODO: Make this function partial - it should not return for Arrow.
266+
// TODO: Make this function partial - it should not return for these variants.
267+
FieldType::Arrow(_) => json!({}),
267268
}
268269
}
269270
}

engine/baml-lib/baml-core/src/ir/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub mod builtin;
12
pub mod ir_hasher;
23
pub mod ir_helpers;
34
pub mod jinja_helpers;

0 commit comments

Comments
 (0)