Skip to content

Conversation

@nathan-barry
Copy link
Contributor

@nathan-barry nathan-barry commented Jun 27, 2025

Overview:

Implements an OpenAI request validation engine wrapper. This adds a generic ValidateEngine that wraps another engine and validates OpenAI API parameters before forwarding requests to the inner engine. Currently just an MVP which validates temperature, waiting for feedback before validating more fields.

Details:

  • Added ValidateEngine<E> generic wrapper in lib/llm/src/engines.rs that can wrap any AsyncEngine implementation
  • Added the ValidateRequest trait in lib/llm/src/engines.rs for Request types
  • Added ValidateRequest implementations for both request types:
    • NvCreateChatCompletionRequest in lib/llm/src/protocols/openai/chat_completions.rs
    • NvCreateCompletionRequest in lib/llm/src/protocols/openai/completions.rs
  • Added Context::rejoin() method in lib/runtime/src/pipeline/context.rs to properly reconstruct request context after validation (since we split it via .into_parts() to get access to the data)
  • Generic AsyncEngine implementation for ValidateEngine in lib/llm/src/engines.rs, which validates any request type implementing ValidateRequest before sending it to the inner engine.

The ValidateEngine follows the existing engine wrapper pattern (similar to EngineDispatcher).

Where should the reviewer start?

The main additions are in lib/llm/src/engines.rs

Let me know whether this looks good. Also, let me know where I should write the tests. I'm developing locally on a MacBook, so doing integration tests might be odd (not too relevant here, but for future PRs). Rust unit tests should be simple though.

Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)

Summary by CodeRabbit

  • New Features

    • Added validation for request parameters, ensuring values such as temperature are within the accepted range before processing.
    • Introduced a validation layer that checks requests and returns errors for invalid input, improving reliability and user feedback.
  • Improvements

    • Enhanced context management, allowing context to be recreated with updated data while preserving shared state.

@copy-pr-bot
Copy link

copy-pr-bot bot commented Jun 27, 2025

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions
Copy link

👋 Hi nathan-barry! Thank you for contributing to ai-dynamo/dynamo.

Just a reminder: The NVIDIA Test Github Validation CI runs an essential subset of the testing framework to quickly catch errors.Your PR reviewers may elect to test the changes comprehensively before approving your changes.

🚀

@github-actions github-actions bot added external-contribution Pull request is from an external contributor feat labels Jun 27, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 27, 2025

Walkthrough

A generic request validation layer was introduced via a new ValidateEngine wrapper and a ValidateRequest trait. Implementations of this trait were added for OpenAI chat and completion request types to validate the temperature parameter. Additionally, a method to reconstruct pipeline contexts with a new data type was added.

Changes

File(s) Change Summary
lib/llm/src/engines.rs Added ValidateEngine<E> wrapper, ValidateRequest trait, and validation logic to the engine dispatch flow.
lib/llm/src/protocols/openai/chat_completions.rs,
lib/llm/src/protocols/openai/completions.rs
Implemented ValidateRequest for chat and completion requests, checking that temperature is within [0.0, 2.0].
lib/runtime/src/pipeline/context.rs Added Context::rejoin method to reconstruct a context with a new current value and preserved internal state.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant ValidateEngine
    participant InnerEngine

    Client->>ValidateEngine: generate(request, context)
    ValidateEngine->>ValidateRequest: validate(request)
    alt Validation fails
        ValidateEngine-->>Client: error
    else Validation succeeds
        ValidateEngine->>InnerEngine: generate(request, context)
        InnerEngine-->>ValidateEngine: response
        ValidateEngine-->>Client: response
    end
Loading

Poem

In the warren, requests now must pass,
Through a validator, sharp as glass.
Temperatures checked, no wild extremes,
Engines hum softly, fulfilling their dreams.
Contexts rejoined, data anew,
This bunny’s code hops safe and true! 🐇✨


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
lib/llm/src/protocols/openai/chat_completions.rs (1)

180-192: LGTM! Consistent validation implementation.

The temperature validation logic is identical to the implementation in lib/llm/src/protocols/openai/completions.rs (lines 284-292), which ensures consistency across request types.

This implementation duplicates the validation logic from the completions.rs file. As suggested in the completions.rs review, consider extracting this into a shared utility function.

🧹 Nitpick comments (1)
lib/llm/src/protocols/openai/completions.rs (1)

281-293: LGTM! Consider extracting common validation logic.

The temperature validation logic is correct and matches the OpenAI API specification. However, this exact validation logic is duplicated in lib/llm/src/protocols/openai/chat_completions.rs (lines 184-191).

Consider extracting the temperature validation into a shared utility function to reduce code duplication:

fn validate_temperature(temperature: Option<f32>) -> Result<(), anyhow::Error> {
    if let Some(temp) = temperature {
        if temp < 0.0 || temp > 2.0 {
            anyhow::bail!("Temperature must be between 0.0 and 2.0, got {}", temp);
        }
    }
    Ok(())
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8b1f2de and 2f29baa.

📒 Files selected for processing (4)
  • lib/llm/src/engines.rs (3 hunks)
  • lib/llm/src/protocols/openai/chat_completions.rs (2 hunks)
  • lib/llm/src/protocols/openai/completions.rs (2 hunks)
  • lib/runtime/src/pipeline/context.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
lib/llm/src/protocols/openai/completions.rs (1)
Learnt from: ishandhanani
PR: ai-dynamo/dynamo#1626
File: lib/llm/src/preprocessor.rs:238-239
Timestamp: 2025-06-24T20:59:35.725Z
Learning: In lib/llm/src/preprocessor.rs, the `sampling_options` call in the `preprocess_request` method is placed in the common section after the match statement on `request.prompt_input_type()`, meaning it applies to both `PromptInput::Tokens` and `PromptInput::Text` request types.
🧬 Code Graph Analysis (2)
lib/llm/src/protocols/openai/completions.rs (2)
lib/llm/src/protocols/openai/chat_completions.rs (1)
  • validate (183-191)
lib/llm/src/engines.rs (1)
  • validate (152-152)
lib/llm/src/protocols/openai/chat_completions.rs (2)
lib/llm/src/protocols/openai/completions.rs (1)
  • validate (284-292)
lib/llm/src/engines.rs (1)
  • validate (152-152)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: pre-merge-rust (.)
  • GitHub Check: pre-merge-rust (lib/runtime/examples)
  • GitHub Check: pre-merge-rust (lib/bindings/python)
  • GitHub Check: Build and Test - vllm
🔇 Additional comments (6)
lib/runtime/src/pipeline/context.rs (1)

51-58: LGTM! Clean implementation of context reconstruction.

The rejoin method provides a clean way to reconstruct a context with a new data type while preserving the shared internal state. This is exactly what's needed for the validation engine to rebuild the request context after validation.

lib/llm/src/protocols/openai/completions.rs (1)

21-21: LGTM! Proper import of ValidateRequest trait.

lib/llm/src/protocols/openai/chat_completions.rs (1)

20-20: LGTM! Proper import of ValidateRequest trait.

lib/llm/src/engines.rs (3)

127-136: LGTM! Clean wrapper engine implementation.

The ValidateEngine follows the same wrapper pattern as EngineDispatcher, providing a consistent approach to engine composition. The simple constructor and generic design make it easy to wrap any existing engine with validation.


150-153: LGTM! Well-designed validation trait.

The ValidateRequest trait provides a clean, extensible interface for request validation. The single method design with anyhow::Error return type allows for flexible error handling and descriptive error messages.


286-308: LGTM! Robust validation engine implementation.

The AsyncEngine implementation for ValidateEngine correctly:

  • Extracts the request and context using into_parts()
  • Validates the request before processing
  • Returns validation errors immediately without forwarding to the inner engine
  • Uses SingleIn::rejoin() to reconstruct the request context after validation
  • Maintains the async engine contract

The error handling and context management are properly implemented.

@nathan-barry
Copy link
Contributor Author

Will remember to do cargo clippy before hand next time (and set it up in my neovim config)

Copy link
Contributor

@ryanolson ryanolson left a comment

Choose a reason for hiding this comment

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

Thanks. I'll let @paulhendricks do more of the review but this conceptually feels right.

We explicitly do not do validation at the http service so that users have the ability to do their own validations and apply their own model specific defaults on the processor (pre/post).

Wrapping this as an engine is a great use of the composition of engines.

We should treat this as an example of OAI validation and use as a reference for writing a custom validator.

This should be applied after model specific defaults are joined into the request (see figments definition of merge vs join).

@nathan-barry
Copy link
Contributor Author

Hey, in this recent commit, I basically just added most of the field verification checks in lib/llm/src/protocols/openai/validate.rs in addition to moving the small amount of verification logic in lib/llm/src/protocols/openai.rs to validate.rs. I believe now all I need to do is add tests.

@grahamking let me know how it looks.

@grahamking
Copy link
Contributor

This is fantastic! Let's get it merged.

@grahamking
Copy link
Contributor

@nathan-barry Can you rebase and fix the conflict? Then I'll merge it.

@nathan-barry
Copy link
Contributor Author

@grahamking got it, will do this after work later today

nathan-barry and others added 3 commits July 1, 2025 14:42
Signed-off-by: Nathan Barry <38043930+nathan-barry@users.noreply.github.com>
@grahamking
Copy link
Contributor

@nathan-barry OK for me to merge it?

@nathan-barry
Copy link
Contributor Author

@grahamking Yeah. If you want me to go back and apply those stylistic changes and also add a bunch of tests cases, I can (let me know what file or folder for the tests, not looked to extensively in that folder). Otherwise, you can just merge it

@grahamking grahamking merged commit ee86bad into ai-dynamo:main Jul 1, 2025
10 checks passed
@grahamking
Copy link
Contributor

Merged! Thanks again.

Tests in a new PR would be lovely. In Rust the unit tests go in the file itself, usually in a test module at the bottom (grep for mod tests for examples). Integration tests go in a tests/ folder in the crate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contribution Pull request is from an external contributor feat size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants