Skip to content

feat(sdk): add ScenarioBuilder class to OO-SDK#748

Merged
sid-rl merged 2 commits into
mainfrom
siddarth/sdk-scenario-builder
Mar 25, 2026
Merged

feat(sdk): add ScenarioBuilder class to OO-SDK#748
sid-rl merged 2 commits into
mainfrom
siddarth/sdk-scenario-builder

Conversation

@sid-rl

@sid-rl sid-rl commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

CodeAnt-AI Description

Add a fluent builder for creating scenarios in the SDK

What Changed

  • Added a new builder flow for creating scenarios with chained setup, then saving them in one step.
  • Scenario setup can now include the environment, problem statement, extra context, metadata, reference output, required variables, required secrets, and validation type.
  • Added support for multiple scorer styles, with weights automatically normalized before the scenario is created.
  • The builder now stops early with clear errors when the problem statement is missing, no scorer is set, or a scorer weight is invalid.

Impact

✅ Shorter scenario setup
✅ Fewer failed scenario creations
✅ Clearer scenario configuration errors

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@codeant-ai

codeant-ai Bot commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@sid-rl sid-rl changed the title add ScenarioBuilder class to OO-SDK feat(sdk): add ScenarioBuilder class to OO-SDK Mar 19, 2026
@sid-rl
sid-rl requested review from alb-rl, dines-rl and james-rl March 19, 2026 00:56
@codeant-ai

codeant-ai Bot commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

Sequence Diagram

This PR adds a new fluent builder flow for creating scenarios from the OO SDK. Users can now start from sdk.scenario.builder(name), compose scenario settings and scorers, then push a validated payload to create and receive a Scenario object.

sequenceDiagram
    participant User
    participant ScenarioOps
    participant ScenarioBuilder
    participant ScenariosAPI
    participant Scenario

    User->>ScenarioOps: builder scenario name
    ScenarioOps-->>User: ScenarioBuilder instance
    User->>ScenarioBuilder: Configure problem environment and scorers
    User->>ScenarioBuilder: push
    ScenarioBuilder->>ScenariosAPI: Create scenario with built params
    ScenariosAPI-->>ScenarioBuilder: Created scenario id
    ScenarioBuilder-->>User: Scenario object from id
Loading

Generated by CodeAnt AI

@codeant-ai codeant-ai Bot added the size:XL This PR changes 500-999 lines, ignoring generated files label Mar 19, 2026
@codeant-ai

codeant-ai Bot commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Missing module
    The new re-export references './scenario-builder'. Confirm that the module file exists at that path, is included in the package build output, and is exposed via package "exports" (if used). Also verify the file is added to source control and to any bundler/tsconfig include settings so consumers won't get a missing-module error.

  • Runtime vs Type export
    Ensure ScenarioBuilder is a runtime value (class/function/const). If './scenario-builder' only exports types, the re-export should use export type { ... }. Also verify whether './scenario-builder' uses a default export — a mismatch (named vs default) would cause runtime import failures for consumers.

  • Possible Circular Import
    A top-level import of ScenarioBuilder was added. This can create a runtime circular dependency if scenario-builder imports anything from this module (or other modules that import this file). Verify runtime import order and consider lazy-loading the builder to avoid circular- import initialization issues.

  • No runtime guard
    The builder method instantiates ScenarioBuilder directly. If the imported symbol is undefined at runtime (due to circular import), this will throw a less-informative TypeError. Add a defensive check or lazy import so the error is clearer and easier to recover from.

  • Environment parameters payload
    The environment parameters object is always created with keys blueprint_id, snapshot_id, and working_directory, but some values may be null. APIs often prefer omitting absent fields rather than sending null. Consider only including keys that have meaningful values to avoid unexpected server behavior.

Comment thread src/sdk/scenario-builder.ts Outdated
Comment on lines +438 to +439
if (weight <= 0) {
throw new Error(`Scorer weight must be positive, got ${weight}`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggestion: addScorer only checks weight <= 0, which allows non-finite values like NaN and Infinity. Those values pass the check but break normalization in build() (s.weight / totalWeight), producing invalid weights (NaN) that will cause malformed scoring payloads and API failures. Validate that weight is finite before accepting it. [logic error]

Severity Level: Major ⚠️
- ❌ Scenario creation payload can contain null scorer weights.
- ⚠️ `runloop.scenario.builder(...).push()` may fail API validation.
Suggested change
if (weight <= 0) {
throw new Error(`Scorer weight must be positive, got ${weight}`);
if (!Number.isFinite(weight) || weight <= 0) {
throw new Error(`Scorer weight must be a finite positive number, got ${weight}`);
Steps of Reproduction ✅
1. Use the public OO-SDK entrypoint `ScenarioOps.builder()` at `src/sdk.ts:1988-1990` to
create a `ScenarioBuilder` instance (normal scenario creation flow exposed to users).

2. Add a scorer with a non-finite computed weight (for example `1/0` or `0/0`) through
`addTestCommandScorer()` at `src/sdk/scenario-builder.ts:156-170`, which forwards to
`addScorer()` at `src/sdk/scenario-builder.ts:437-442`.

3. In `addScorer()` (`src/sdk/scenario-builder.ts:438`), `if (weight <= 0)` does not
reject `NaN`/`Infinity`, so invalid weight is stored in `_scorers`.

4. Call `push()` (`src/sdk/scenario-builder.ts:431-434`) or `build()` (`:366-408`):
normalization computes `weight: s.weight / totalWeight` (`:378-382`), then request
serialization in `src/core.ts:335` uses `JSON.stringify`, which serializes non-finite
numbers to `null`, producing invalid scorer weights in `/v1/scenarios` create payload
(`src/resources/scenarios/scenarios.ts:37-39`).
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/sdk/scenario-builder.ts
**Line:** 438:439
**Comment:**
	*Logic Error: `addScorer` only checks `weight <= 0`, which allows non-finite values like `NaN` and `Infinity`. Those values pass the check but break normalization in `build()` (`s.weight / totalWeight`), producing invalid weights (`NaN`) that will cause malformed scoring payloads and API failures. Validate that weight is finite before accepting it.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

@codeant-ai

codeant-ai Bot commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

CodeAnt AI finished reviewing your PR.

@github-actions

github-actions Bot commented Mar 19, 2026

Copy link
Copy Markdown

✅ Object Smoke Tests & Coverage Report

Test Results

✅ All smoke tests passed

Coverage Results

Metric Coverage Required Status
Functions 100% 100%
Lines 90.09% - ℹ️
Branches 69.52% - ℹ️
Statements 88.98% - ℹ️

Coverage Requirement: 100% function coverage (all public methods must be called in smoke tests)

✅ All tests passed and all object methods are covered!

View detailed coverage report
File Functions Lines Branches
src/sdk.ts ✅ 100% 85.78% 72.58%
src/sdk/agent.ts ✅ 100% 100% 100%
src/sdk/blueprint.ts ✅ 100% 100% 80%
src/sdk/devbox.ts ✅ 100% 91.81% 96.96%
src/sdk/execution-result.ts ✅ 100% 92.68% 70.83%
src/sdk/execution.ts ✅ 100% 95.65% 87.5%
src/sdk/gateway-config.ts ✅ 100% 100% 100%
src/sdk/mcp-config.ts ✅ 100% 100% 100%
src/sdk/network-policy.ts ✅ 100% 100% 100%
src/sdk/scenario-builder.ts ✅ 100% 98.46% 80.7%
src/sdk/scenario-run.ts ✅ 100% 96.87% 50%
src/sdk/scenario.ts ✅ 100% 100% 100%
src/sdk/scorer.ts ✅ 100% 100% 100%
src/sdk/secret.ts ✅ 100% 100% 100%
src/sdk/snapshot.ts ✅ 100% 100% 100%
src/sdk/storage-object.ts ✅ 100% 80% 48.93%

📋 View workflow run

@sid-rl
sid-rl force-pushed the siddarth/sdk-scenario-builder branch from a4e4e2f to e6202b8 Compare March 19, 2026 01:21

@james-rl james-rl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This looks good to me -- I see there are some smoke tests failing but I don't think they're caused by changes in this code. Still, you should make sure they pass before merging this.

@sid-rl
sid-rl force-pushed the siddarth/sdk-scenario-builder branch from e6202b8 to 7017e8e Compare March 24, 2026 23:42
@codeant-ai

codeant-ai Bot commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

CodeAnt AI is running Incremental review


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai Bot added size:XL This PR changes 500-999 lines, ignoring generated files and removed size:XL This PR changes 500-999 lines, ignoring generated files labels Mar 24, 2026
if (!Number.isFinite(weight) || weight <= 0) {
throw new Error(`Scorer weight must be a finite positive number, got ${weight}`);
}
this._scorers.push({ name, weight, scorer });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggestion: Scorer names are pushed without enforcing the API contract ([a-zA-Z0-9_-] only), so invalid names pass build() and fail later during push() with a server-side validation error. Add local validation in addScorer to fail fast with a clear message. [logic error]

Severity Level: Major ⚠️
- ⚠️ push() may fail with server validation error.
- ⚠️ Scenario creation flow gets late, unclear failure.
Suggested change
this._scorers.push({ name, weight, scorer });
if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
throw new Error('Scorer name must only contain [a-zA-Z0-9_-]');
}
Steps of Reproduction ✅
1. Call SDK entrypoint `ScenarioOps.builder(name)` in `src/sdk.ts:1988`, which returns
`new ScenarioBuilder(name, this.client)`.

2. Add a scorer with an invalid name (for example `bad name`) through
`addShellCommandScorer()` in `src/sdk/scenario-builder.ts:182`, which forwards to
`addScorer()` at `src/sdk/scenario-builder.ts:178`.

3. Observe `addScorer()` only validates weight at `src/sdk/scenario-builder.ts:179-181`
and pushes name unchanged at `src/sdk/scenario-builder.ts:182`.

4. Call `build()` (`src/sdk/scenario-builder.ts:107`) and see invalid `name` included in
`scoring_function_parameters`.

5. This violates the documented API contract in `src/resources/scenarios/scenarios.ts:16`
("Names must only contain [a-zA-Z0-9_-]"), so failure is deferred to `push()` API call
path (`src/sdk/scenario-builder.ts:172-175` -> `client.scenarios.create`).
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/sdk/scenario-builder.ts
**Line:** 441:441
**Comment:**
	*Logic Error: Scorer names are pushed without enforcing the API contract (`[a-zA-Z0-9_-]` only), so invalid names pass `build()` and fail later during `push()` with a server-side validation error. Add local validation in `addScorer` to fail fast with a clear message.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

@codeant-ai

codeant-ai Bot commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

CodeAnt AI Incremental review completed.

@sid-rl
sid-rl merged commit f80ed4c into main Mar 25, 2026
9 of 11 checks passed
@sid-rl
sid-rl deleted the siddarth/sdk-scenario-builder branch March 25, 2026 18:15
@stainless-app stainless-app Bot mentioned this pull request Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants