Skip to content

Conversation

@sxlijin
Copy link
Collaborator

@sxlijin sxlijin commented Sep 19, 2025

This also removes a bunch of panics, because if we can't resolve a .baml file to a baml_src project we will no longer crash.

@vercel
Copy link

vercel bot commented Sep 19, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
promptfiddle Skipped Skipped Sep 23, 2025 5:56pm

@sxlijin sxlijin temporarily deployed to boundary-tools-dev September 19, 2025 23:34 — with GitHub Actions Inactive
@sxlijin sxlijin temporarily deployed to boundary-tools-dev September 19, 2025 23:34 — with GitHub Actions Inactive
@sxlijin sxlijin temporarily deployed to boundary-tools-dev September 19, 2025 23:34 — with GitHub Actions Inactive
@github-actions
Copy link

@entelligence-ai-pr-reviews
Copy link

🔒 Entelligence AI Vulnerability Scanner

No security vulnerabilities found!

Your code passed our comprehensive security analysis.


@sxlijin sxlijin enabled auto-merge September 19, 2025 23:37
@entelligence-ai-pr-reviews
Copy link

Review Summary

🏷️ Draft Comments (6)

Skipped posting 6 draft comments that were valid but scored below your review threshold (>=10/15). Feel free to update them here.

engine/language_server/src/server/api/diagnostics.rs (1)

64-72: diagnostics.clone() in the for-loop of publish_diagnostics causes unnecessary cloning of potentially large diagnostic maps, doubling memory and CPU usage for each publish.

📊 Impact Scores:

  • Production Impact: 2/5
  • Fix Specificity: 5/5
  • Urgency Impact: 2/5
  • Total Score: 9/15

🤖 AI Agent Prompt (Copy & Paste Ready):

In engine/language_server/src/server/api/diagnostics.rs, lines 64-72, the code clones the entire `diagnostics` map before iterating, which is inefficient for large projects. Refactor the loop to iterate directly over `diagnostics` without cloning, preserving the original formatting and logic.

engine/language_server/src/server/api/notifications/did_change_watched_files.rs (1)

54-54: The function reloads the entire session (session.reload(...)) on any relevant file event, which can be expensive for large projects and may cause unnecessary work if only a subset of files changed.

📊 Impact Scores:

  • Production Impact: 3/5
  • Fix Specificity: 2/5
  • Urgency Impact: 2/5
  • Total Score: 7/15

🤖 AI Agent Prompt (Copy & Paste Ready):

In engine/language_server/src/server/api/notifications/did_change_watched_files.rs, line 54, the code calls `session.reload(...)` on every relevant file event, which can be expensive for large projects and may cause unnecessary work if only a subset of files changed. Refactor this logic to only reload the affected project(s) or files, rather than the entire session, to improve performance and scalability.

engine/language_server/src/server/api/notifications/did_close.rs (1)

56-56: The function session.reload(Some(notifier)) is called on every document close, which may trigger expensive project-wide reloads even for frequent or batch document closes, causing significant performance degradation for large projects.

📊 Impact Scores:

  • Production Impact: 3/5
  • Fix Specificity: 2/5
  • Urgency Impact: 2/5
  • Total Score: 7/15

🤖 AI Agent Prompt (Copy & Paste Ready):

In engine/language_server/src/server/api/notifications/did_close.rs, lines 56-56, the code calls `session.reload(Some(notifier))` on every document close, which can cause significant performance issues for large projects due to repeated expensive reloads. Refactor this logic to avoid triggering a full reload on every close—consider batching, deferring, or otherwise minimizing reload frequency while maintaining correctness.

engine/language_server/src/server/api/requests/code_lens.rs (2)

66-67: mk_range uses span.start and span.end as character indices, but these may be byte offsets, leading to incorrect LSP ranges and misaligned code lenses in editors.

📊 Impact Scores:

  • Production Impact: 3/5
  • Fix Specificity: 2/5
  • Urgency Impact: 2/5
  • Total Score: 7/15

🤖 AI Agent Prompt (Copy & Paste Ready):

In engine/language_server/src/server/api/requests/code_lens.rs, lines 66-67, the mk_range closure constructs LSP Position objects using span.start and span.end, which may be byte offsets rather than character indices. This can cause code lenses to appear at incorrect positions in editors. Update mk_range to use character indices (e.g., span.start_character() and span.end_character()) instead of raw byte offsets. If such methods do not exist, implement the conversion from byte offset to character index for the line.

114-143: list_function_test_pairs likely produces N^2 code lenses for N test blocks, causing quadratic scaling and UI clutter for large projects.

📊 Impact Scores:

  • Production Impact: 3/5
  • Fix Specificity: 4/5
  • Urgency Impact: 2/5
  • Total Score: 9/15

🤖 AI Agent Prompt (Copy & Paste Ready):

In engine/language_server/src/server/api/requests/code_lens.rs, lines 114-143, the current code generates N^2 code lenses for test blocks due to denormalized output from `list_function_test_pairs`, causing quadratic scaling and UI clutter. Refactor this block to deduplicate test/function pairs so that only one code lens per unique test/function is generated. Use a HashSet to track and filter out duplicates. Preserve the original formatting and logic as much as possible.

engine/language_server/src/server/api/requests/completion.rs (1)

34-36: session.get_or_create_project(&path) returns Ok(project) but project is not used, causing the function to always return Ok(None) and never provide completions, breaking expected completion functionality.

📊 Impact Scores:

  • Production Impact: 4/5
  • Fix Specificity: 2/5
  • Urgency Impact: 3/5
  • Total Score: 9/15

🤖 AI Agent Prompt (Copy & Paste Ready):

In engine/language_server/src/server/api/requests/completion.rs, lines 34-36, the code obtains a `project` from `session.get_or_create_project(&path)` but does not use it, and always returns `Ok(None)`. This breaks completion functionality, as no completions are ever returned. Update the function to use the `project` variable to generate and return actual completions, restoring the expected behavior.

🔍 Comments beyond diff scope (3)
engine/language_server/src/server/api.rs (1)

84-110: for (_, project) in projects.iter() in getBAMLFunctions locks and iterates all projects, calling .list_functions() for each; if projects is large, this can cause significant contention and latency, especially under high concurrency.
Category: performance


engine/language_server/src/server/api/requests/hover.rs (1)

38-68: Multiple calls to project.lock() within the same function (lines 38, 41, 60) cause repeated locking/unlocking, which can lead to resource contention and measurable latency under high concurrency.
Category: performance


engine/language_server/src/server/api/requests/rename.rs (1)

43-43: session.get_or_create_project(&path) returns Ok(project) but project.lock() can panic if the mutex is poisoned, causing a crash instead of graceful error handling.
Category: correctness


Comment on lines +100 to 104
tracing::info!(
"BAML file not in baml_src directory, not publishing diagnostics: {}",
file_url
);
return Ok(());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correctness: publish_session_lsp_diagnostics silently returns without notifying the client with a diagnostic when a .baml file is outside baml_src, so editors may show stale errors or no feedback.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In engine/language_server/src/server/api/diagnostics.rs, lines 100-104, when a `.baml` file is not in a `baml_src` directory, the function returns early without notifying the client, which can leave editors with stale or missing diagnostics. Update this block to call `notifier.notify::<lsp_types::notification::PublishDiagnostics>(not_in_baml_src_diagnostic(file_url)).ok();` before returning, so the client always receives a diagnostic explaining the issue.
📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
tracing::info!(
"BAML file not in baml_src directory, not publishing diagnostics: {}",
file_url
);
return Ok(());
tracing::info!(
"BAML file not in baml_src directory, not publishing diagnostics: {}",
file_url
);
notifier.notify::<lsp_types::notification::PublishDiagnostics>(not_in_baml_src_diagnostic(file_url)).ok();
return Ok(());

Comment on lines +27 to +32
if params.changes.iter().any(|change| {
let Ok(path) = change.uri.to_file_path() else {
return true;
};
session.get_or_create_project(&path).is_err()
}) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correctness: params.changes.iter().any(...) returns true if ANY change cannot be resolved to a project, causing the function to return early and skip processing ALL changes, even if some are valid; this can suppress updates for valid files.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In engine/language_server/src/server/api/notifications/did_change_watched_files.rs, lines 27-32, the code returns early if ANY file change cannot be resolved to a project, which causes all changes to be ignored even if some are valid. Change the logic so that it only returns early if ALL changes are invalid (i.e., cannot be resolved to a project). Replace the use of `.any(...)` with `.all(...)` and update the condition accordingly.
📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
if params.changes.iter().any(|change| {
let Ok(path) = change.uri.to_file_path() else {
return true;
};
session.get_or_create_project(&path).is_err()
}) {
let all_invalid = params.changes.iter().all(|change| {
let Ok(path) = change.uri.to_file_path() else {
return true;
};
session.get_or_create_project(&path).is_err()
});
if all_invalid {
return Ok(());
}

Comment on lines +79 to +89
let locked = project.lock();
let default_flags = vec!["beta".to_string()];
let effective_flags = session
.baml_settings
.feature_flags
.as_ref()
.unwrap_or(&default_flags);
let client_version = session.baml_settings.get_client_version();

let generator_version = locked.get_common_generator_version();
send_generator_version(&notifier, &locked, generator_version.as_ref().ok());
} else {
tracing::error!("Failed to get or create project for path: {:?}", file_path);
show_err_msg!("Failed to get or create project for path: {:?}", file_path);
}
tracing::info!("after get_or_create_project");
let generator_version = locked.get_common_generator_version();
send_generator_version(&notifier, &locked, generator_version.as_ref().ok());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correctness: project is locked and used after the early return, but if session.get_or_create_project(&path) fails, the function returns early and project is never defined, which is correct; however, if get_or_create_project returns Ok(project) but the lock fails (e.g., poisoned mutex), this will panic at runtime.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In engine/language_server/src/server/api/notifications/did_open.rs, lines 79-89, the code calls `project.lock()` directly, which can panic if the mutex is poisoned. Change this to handle the poisoned lock gracefully: use `match project.lock()` and return early with an error log if locking fails, instead of panicking. Apply this fix to ensure runtime stability.
📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
let locked = project.lock();
let default_flags = vec!["beta".to_string()];
let effective_flags = session
.baml_settings
.feature_flags
.as_ref()
.unwrap_or(&default_flags);
let client_version = session.baml_settings.get_client_version();
let generator_version = locked.get_common_generator_version();
send_generator_version(&notifier, &locked, generator_version.as_ref().ok());
} else {
tracing::error!("Failed to get or create project for path: {:?}", file_path);
show_err_msg!("Failed to get or create project for path: {:?}", file_path);
}
tracing::info!("after get_or_create_project");
let generator_version = locked.get_common_generator_version();
send_generator_version(&notifier, &locked, generator_version.as_ref().ok());
let locked = match project.lock() {
Ok(locked) => locked,
Err(poisoned) => {
tracing::error!("Project lock poisoned");
return Ok(());
}
};
let default_flags = vec!["beta".to_string()];
let effective_flags = session
.baml_settings
.feature_flags
.as_ref()
.unwrap_or(&default_flags);
let client_version = session.baml_settings.get_client_version();
let generator_version = locked.get_common_generator_version();
send_generator_version(&notifier, &locked, generator_version.as_ref().ok());

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Review: Here are some suggestions.

Reply with @codex fix comments to fix any unresolved comments.

About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you open a pull request for review, mark a draft as ready, or comment "@codex review". If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex fix this CI failure" or "@codex address that feedback".

Comment on lines +27 to 33
if params.changes.iter().any(|change| {
let Ok(path) = change.uri.to_file_path() else {
return true;
};
session.get_or_create_project(&path).is_err()
}) {
return Ok(());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Process batches even when some watched files are outside baml_src

The new early-return in DidChangeWatchedFiles now triggers whenever any change in the batch cannot be resolved to a baml project. File watching APIs often deliver mixed batches (e.g. a baml_src file together with a non-BAML file). In such cases this condition skips the entire handler, so the valid BAML file update will never reload the session or republish diagnostics. The previous logic only returned when no change was under baml_src. Consider checking that at least one change resolves to a project (all/any inversion) so unrelated files do not block handling of legitimate ones.

Useful? React with 👍 / 👎.

@github-actions
Copy link

@github-actions
Copy link

@github-actions
Copy link

@sxlijin sxlijin added this pull request to the merge queue Sep 23, 2025
Merged via the queue into canary with commit 6bf3299 Sep 23, 2025
24 of 25 checks passed
@sxlijin sxlijin deleted the sam/non-baml branch September 23, 2025 18:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants