Skip to content

Commit

Permalink
Fix stack overflow when calculating wasm function signature (#1100)
Browse files Browse the repository at this point in the history
<!-- ELLIPSIS_HIDDEN -->



> [!IMPORTANT]
> Fix stack overflow in WebAssembly function signature calculation and
improve logging, error handling, and testing.
> 
>   - **Behavior**:
> - Fix stack overflow in `get_dummy_value()` in `mod.rs` by correctly
handling `Constrained` field types.
> - Initialize `wasm_logger` in `on_wasm_init()` in `mod.rs` to enable
logging of `info` messages.
>   - **Debugging**:
> - Add `Debug` trait to `WasmError`, `WasmFunction`, `WasmSpan`,
`WasmGeneratorConfig`, `WasmParentFunction`, `WasmTestCase`, and
`WasmParam` in `mod.rs`.
>   - **Testing**:
> - Add `test_diagnostics_no_errors_2()` in `test_file_manager.rs` to
verify diagnostics with no errors.
> - Update `test_diagnostics_no_errors()` in `test_file_manager.rs` to
include function listing.
>   - **TypeScript**:
> - Fix `requestDiagnostics()` in `baml_project_manager.ts` to handle
undefined runtime.
>     - Add error handling for `runtime_updated` request in `server.ts`.
> 
> <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 48fae24. It will automatically
update as commits are pushed.</sup>

<!-- ELLIPSIS_HIDDEN -->
  • Loading branch information
aaronvg authored Oct 25, 2024
1 parent cb5ce76 commit aa736ed
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 17 deletions.
19 changes: 12 additions & 7 deletions engine/baml-schema-wasm/src/runtime_wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ pub fn on_wasm_init() {
const LOG_LEVEL: log::Level = log::Level::Warn;
}
};
// This line is required if we want to see normal log::info! messages in JS console logs.
wasm_logger::init(wasm_logger::Config::new(LOG_LEVEL));
match console_log::init_with_level(LOG_LEVEL) {
Ok(_) => web_sys::console::log_1(
&format!("Initialized BAML runtime logging as log::{}", LOG_LEVEL).into(),
Expand Down Expand Up @@ -140,6 +142,7 @@ impl WasmDiagnosticError {
}

#[wasm_bindgen(getter_with_clone, inspectable)]
#[derive(Debug)]
pub struct WasmError {
#[wasm_bindgen(readonly)]
pub r#type: String,
Expand Down Expand Up @@ -282,7 +285,7 @@ pub struct WasmRuntime {
}

#[wasm_bindgen(getter_with_clone, inspectable)]
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct WasmFunction {
#[wasm_bindgen(readonly)]
pub name: String,
Expand All @@ -297,7 +300,7 @@ pub struct WasmFunction {
}

#[wasm_bindgen(getter_with_clone, inspectable)]
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct WasmSpan {
#[wasm_bindgen(readonly)]
pub file_path: String,
Expand All @@ -312,7 +315,7 @@ pub struct WasmSpan {
}

#[wasm_bindgen(getter_with_clone, inspectable)]
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct WasmGeneratorConfig {
#[wasm_bindgen(readonly)]
pub output_type: String,
Expand Down Expand Up @@ -348,7 +351,7 @@ impl Default for WasmSpan {
}

#[wasm_bindgen(getter_with_clone, inspectable)]
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct WasmParentFunction {
#[wasm_bindgen(readonly)]
pub start: usize,
Expand All @@ -359,7 +362,7 @@ pub struct WasmParentFunction {
}

#[wasm_bindgen(getter_with_clone, inspectable)]
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct WasmTestCase {
#[wasm_bindgen(readonly)]
pub name: String,
Expand All @@ -374,7 +377,7 @@ pub struct WasmTestCase {
}

#[wasm_bindgen(getter_with_clone, inspectable)]
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct WasmParam {
#[wasm_bindgen(readonly)]
pub name: String,
Expand Down Expand Up @@ -783,7 +786,9 @@ fn get_dummy_value(
Some(format!("({},)", dummy))
}
baml_runtime::FieldType::Optional(_) => None,
baml_runtime::FieldType::Constrained{ base, .. } => get_dummy_value(indent, allow_multiline, t)
baml_runtime::FieldType::Constrained { base, .. } => {
get_dummy_value(indent, allow_multiline, base)
}
}
}

Expand Down
47 changes: 40 additions & 7 deletions engine/baml-schema-wasm/tests/test_file_manager.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Run from the baml-schema-wasm folder with:
// wasm-pack test --node
#[cfg(test)]
mod tests {
use std::collections::HashMap;
Expand All @@ -17,13 +19,7 @@ mod tests {
/// Sample BAML content for testing.
fn sample_baml_content() -> String {
r##"
generator lang_python {
language python
project_root "../"
test_command "poetry run pytest"
install_command "poetry add baml@latest"
package_version_command "poetry show baml"
}
class Email {
subject string
Expand Down Expand Up @@ -139,4 +135,41 @@ mod tests {

assert!(diagnostics.errors().is_empty());
}

#[wasm_bindgen_test]
fn test_diagnostics_no_errors_2() {
wasm_logger::init(wasm_logger::Config::new(log::Level::Info));
let sample_baml_content = r##"
function PredictAgeBare(inp: string @assert(big_enough, {{this|length > 1}}) ) -> int {
client "openai/gpt-4o"
prompt #"
Using your understanding of the historical popularity
of names, predict the age of a person with the name
{{ inp }} in years. Also predict their genus and
species. It's Homo sapiens (with exactly that spelling).
{{ctx.output_format}}
"#
}
"##;
let mut files = HashMap::new();
files.insert("error.baml".to_string(), sample_baml_content.to_string());
let files_js = to_value(&files).unwrap();
let project = WasmProject::new("baml_src", files_js)
.map_err(JsValue::from)
.unwrap();

let env_vars = [("OPENAI_API_KEY", "12345")]
.iter()
.cloned()
.collect::<HashMap<_, _>>();
let env_vars_js = to_value(&env_vars).unwrap();

let current_runtime = project.runtime(env_vars_js).map_err(JsValue::from).unwrap();
let diagnostics = project.diagnostics(&current_runtime);
current_runtime.list_functions();

assert!(diagnostics.errors().is_empty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ class Project {
.map(([path, content]) => [URI.file(path).toString(), content]),
)
const diagnostics = this.wasmProject.diagnostics(this.current_runtime)
this.onSuccess(this.wasmProject.diagnostics(this.current_runtime), fileMap)
this.onSuccess(diagnostics, fileMap)
}
}

Expand Down Expand Up @@ -622,7 +622,11 @@ class BamlProjectManager {
await this.wrapAsync(async () => {
for (const project of this.projects.values()) {
project.requestDiagnostics()
this.notifier({ type: 'runtime_updated', root_path: project.rootPath(), files: project.files() })
if (project.runtime()) {
this.notifier({ type: 'runtime_updated', root_path: project.rootPath(), files: project.files() })
} else {
console.log('undefined runtime')
}
}
})
}
Expand Down
4 changes: 3 additions & 1 deletion typescript/vscode-ext/packages/language-server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ export function startServer(options?: LSOptions): void {
switch (params.type) {
case 'runtime_updated':
// console.log(`runtime_updated today! ${Object.keys(params.files).length}: ${Object.entries(params.files).length}`)
connection.sendRequest('runtime_updated', params)
connection.sendRequest('runtime_updated', params).catch((e) => {
console.error('Error sending runtime_updated: ' + e)
})
break
case 'diagnostic':
params.errors.forEach(([uri, diagnostics]) => {
Expand Down

0 comments on commit aa736ed

Please sign in to comment.