Skip to content

Commit df6ee12

Browse files
imalsogreghellovaiegolsxlijinJesús Lapastora
authored
Merge Egor's Mermaid (#2381)
<!-- ELLIPSIS_HIDDEN --> > [!IMPORTANT] > This pull request integrates Mermaid diagrams for function flows in the BAML project, enhancing the UI with new components and controls for diagram interaction and state management. > > - **Mermaid Integration**: > - Add `mermaid` and `svg-pan-zoom` dependencies to `package.json`. > - Implement `MermaidGraphView` component in `MermaidGraphView.tsx` for rendering function flow diagrams. > - Use `mermaid` to generate and render diagrams, with custom CSS for styling. > - **UI Enhancements**: > - Add zoom and reset controls to `MermaidGraphView` for better user interaction. > - Integrate `MermaidGraphView` into `PromptRenderWrapper` with a new tab for viewing diagrams. > - Update `PreviewToolbar` to include a toggle for beta features, enabling the Mermaid graph view. > - **State Management**: > - Introduce `functionGraphAtom` in `atoms-orch-graph.ts` to manage the state of the function graph. > - Use Jotai atoms to handle feature flags and runtime configurations. > - **Error Handling**: > - Enhance error rendering in `EnhancedErrorRenderer.tsx` with custom error renderers and improved UI feedback. > > <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 3c8cb7f. 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: hellovai <vbv@boundaryml.com> Co-authored-by: egol <egoriluk@gmail.com> Co-authored-by: Samuel Lijin <sam@boundaryml.com> Co-authored-by: Jesús Lapastora <jesus@boundaryml.com>
1 parent d976c55 commit df6ee12

89 files changed

Lines changed: 5957 additions & 187 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.

.cursor/rules/jj-workflow.mdc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
---
2-
description: Guide for using fine-grained JJ commits during development.
3-
globs:
4-
alwaysApply: true
2+
alwaysApply: false
53
---
6-
74
Whenever doing work:
85
- See if you are on a bookmark or a commit with a name or description appropriate to that task
96
- Use fine-grained tasks - if you're creating tests for TDD, put that in a separate commit

engine/baml-compiler/src/hir/lowering.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ fn lower_stmt(stmt: &ast::Stmt) -> Statement {
375375
is_mutable,
376376
expr,
377377
span,
378+
annotations: _,
378379
}) => {
379380
let lifted_expr = Expression::from_ast(expr);
380381

@@ -397,6 +398,7 @@ fn lower_stmt(stmt: &ast::Stmt) -> Statement {
397398
iterator,
398399
body,
399400
span,
401+
annotations: _,
400402
}) => {
401403
// Lower for loop to HIR
402404
let lifted_iterator = Expression::from_ast(iterator);
@@ -410,8 +412,8 @@ fn lower_stmt(stmt: &ast::Stmt) -> Statement {
410412
}
411413
}
412414
ast::Stmt::Expression(expr) => Statement::Expression {
413-
expr: Expression::from_ast(expr),
414-
span: expr.span().clone(),
415+
expr: Expression::from_ast(&expr.expr),
416+
span: expr.span.clone(),
415417
},
416418
ast::Stmt::Semicolon(expr) => Statement::Semicolon {
417419
expr: Expression::from_ast(expr),

engine/baml-compiler/src/thir.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ impl<T: Clone> Statement<T> {
705705
Statement::Return { expr, span: _ } => {
706706
format!("return {}", expr.dump_str())
707707
}
708-
Statement::Expression { expr, span: _ } => expr.dump_str().to_string(),
708+
Statement::Expression { expr, span: _ } => expr.dump_str(),
709709
Statement::SemicolonExpression { expr, span: _ } => expr.dump_str().to_string(),
710710
Statement::While {
711711
condition,

engine/baml-lib/ast/Cargo.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ regex.workspace = true
3131
pretty_assertions.workspace = true
3232
unindent = "0.2.3"
3333

34+
[[example]]
35+
name = "generate_mermaid_ast"
36+
path = "examples/generate_mermaid_ast.rs"
37+
38+
[[example]]
39+
name = "generate_mermaid_headers"
40+
path = "examples/generate_mermaid_headers.rs"
41+
3442
[features]
3543
debug_parser = []
36-
# default = ["debug_parser"]
44+
#default = ["debug_parser"]
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use std::{env, fs, path::Path};
2+
3+
use internal_baml_ast::{parse, MermaidDiagramGenerator};
4+
use internal_baml_diagnostics::SourceFile;
5+
6+
fn main() {
7+
// Get command line arguments
8+
let args: Vec<String> = env::args().collect();
9+
10+
if args.len() < 2 || args.len() > 3 {
11+
eprintln!("Usage: {} [--fancy] <path-to-baml-file>", args[0]);
12+
eprintln!("Example: {} example.baml", args[0]);
13+
eprintln!("Example: {} --fancy example.baml", args[0]);
14+
std::process::exit(1);
15+
}
16+
17+
let (baml_file_path, use_fancy) = if args.len() == 3 && args[1] == "--fancy" {
18+
(&args[2], true)
19+
} else {
20+
(&args[1], false)
21+
};
22+
23+
// Check if file exists and has .baml extension
24+
let path = Path::new(baml_file_path);
25+
if !path.exists() {
26+
eprintln!("Error: File '{baml_file_path}' does not exist");
27+
std::process::exit(1);
28+
}
29+
30+
if path.extension().and_then(|s| s.to_str()) != Some("baml") {
31+
eprintln!("Error: File '{baml_file_path}' does not have a .baml extension");
32+
std::process::exit(1);
33+
}
34+
35+
// Read the BAML file
36+
let baml_source = match fs::read_to_string(path) {
37+
Ok(content) => content,
38+
Err(err) => {
39+
eprintln!("Error reading file '{baml_file_path}': {err}");
40+
std::process::exit(1);
41+
}
42+
};
43+
44+
// Create a SourceFile
45+
let source = SourceFile::from((path.to_path_buf(), baml_source));
46+
let root_path = Path::new(".");
47+
48+
// Parse the BAML source code
49+
match parse(root_path, &source) {
50+
Ok((ast, _diagnostics)) => {
51+
// Print the AST
52+
dbg!(&ast);
53+
54+
// Generate Mermaid diagram with optional styling
55+
let mermaid_diagram =
56+
MermaidDiagramGenerator::generate_ast_diagram_with_styling(&ast, use_fancy);
57+
58+
println!(
59+
"Generated Mermaid Diagram for '{}' (styling: {}):",
60+
baml_file_path,
61+
if use_fancy { "enabled" } else { "disabled" }
62+
);
63+
println!("{mermaid_diagram}");
64+
65+
// You can copy the output and paste it into any Mermaid renderer
66+
println!("\nTo visualize this diagram:");
67+
println!("1. Copy the output above");
68+
println!("2. Go to https://mermaid.live/");
69+
println!("3. Paste the diagram code");
70+
println!("4. View the rendered AST diagram!");
71+
}
72+
Err(err) => {
73+
eprintln!("Failed to parse BAML source: {err:?}");
74+
std::process::exit(1);
75+
}
76+
}
77+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use std::path::Path;
2+
3+
use internal_baml_ast::{parse, BamlVisDiagramGenerator};
4+
use internal_baml_diagnostics::SourceFile;
5+
6+
fn main() {
7+
let mut args = std::env::args().skip(1);
8+
let Some(input_path) = args.next() else {
9+
eprintln!("Usage: generate_mermaid_headers <path/to/file.baml>");
10+
std::process::exit(2);
11+
};
12+
13+
let path = std::path::PathBuf::from(&input_path);
14+
let contents = match std::fs::read_to_string(&path) {
15+
Ok(s) => s,
16+
Err(e) => {
17+
eprintln!("Failed to read {input_path}: {e}");
18+
std::process::exit(1);
19+
}
20+
};
21+
22+
let source = SourceFile::new_allocated(path.clone(), contents.into());
23+
let (ast, diags) = match parse(Path::new("."), &source) {
24+
Ok(res) => res,
25+
Err(diags) => {
26+
eprintln!("Parse errors:\n{}", diags.to_pretty_string());
27+
std::process::exit(1);
28+
}
29+
};
30+
if diags.has_errors() {
31+
eprintln!("Parse errors:\n{}", diags.to_pretty_string());
32+
std::process::exit(1);
33+
}
34+
35+
// Nicely styled header graph
36+
let mermaid = BamlVisDiagramGenerator::generate_with_styling(&ast, true);
37+
println!("{mermaid}");
38+
}

engine/baml-lib/ast/src/ast.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,31 @@ mod traits;
2121
mod type_builder_block;
2222
mod type_expression_block;
2323
mod value_expression_block;
24+
25+
pub mod baml_vis;
26+
pub mod header_collector;
27+
pub mod mermaid_debug;
2428
pub use app::App;
2529
pub use argument::{Argument, ArgumentId, ArgumentsList};
2630
pub use assignment::Assignment;
2731
pub use attribute::{Attribute, AttributeContainer, AttributeId};
32+
pub use baml_vis::BamlVisDiagramGenerator;
2833
pub use config::ConfigBlockProperty;
2934
pub use expr::{ExprFn, TopLevelAssignment};
3035
pub use expression::{
3136
BinaryOperator, ClassConstructor, ClassConstructorField, Expression, ExpressionBlock,
3237
RawString, UnaryOperator,
3338
};
3439
pub use field::{Field, FieldArity, FieldType};
40+
pub use header_collector::{HeaderCollector, HeaderIndex, RenderableHeader, ScopeId};
3541
pub use identifier::{Identifier, RefIdentifier};
3642
pub use indentation_type::IndentationType;
3743
pub use internal_baml_diagnostics::Span;
44+
pub use mermaid_debug::MermaidDiagramGenerator;
3845
pub use newline_type::NewlineType;
3946
pub use stmt::{
40-
AssertStmt, AssignOp, AssignOpStmt, AssignStmt, CForLoopStmt, ForLoopStmt, LetStmt, ReturnStmt,
41-
Stmt, WhileStmt,
47+
AssertStmt, AssignOp, AssignOpStmt, AssignStmt, CForLoopStmt, ExprStmt, ForLoopStmt, Header,
48+
LetStmt, ReturnStmt, Stmt, WhileStmt,
4249
};
4350
pub use template_string::TemplateString;
4451
pub use top::Top;
@@ -103,6 +110,18 @@ impl From<u32> for TypeExpId {
103110
}
104111
}
105112

113+
impl From<u32> for ValExpId {
114+
fn from(id: u32) -> Self {
115+
ValExpId(id)
116+
}
117+
}
118+
119+
impl From<u32> for ExprFnId {
120+
fn from(id: u32) -> Self {
121+
ExprFnId(id)
122+
}
123+
}
124+
106125
impl std::ops::Index<TypeExpId> for Ast {
107126
type Output = TypeExpressionBlock;
108127

@@ -259,6 +278,13 @@ impl TopId {
259278
}
260279
}
261280

281+
pub fn as_generator_id(self) -> Option<ValExpId> {
282+
match self {
283+
TopId::Generator(id) => Some(id),
284+
_ => None,
285+
}
286+
}
287+
262288
pub fn as_template_string_id(self) -> Option<TemplateStringId> {
263289
match self {
264290
TopId::TemplateString(id) => Some(id),

0 commit comments

Comments
 (0)