Skip to content

feat: options allow overrides#97

Open
constantinius wants to merge 1 commit intomainfrom
constantinius/feat/options-allow-overrides
Open

feat: options allow overrides#97
constantinius wants to merge 1 commit intomainfrom
constantinius/feat/options-allow-overrides

Conversation

@constantinius
Copy link
Collaborator

@constantinius constantinius commented Mar 12, 2026

Add support for object-style option values in framework config.json with per-value config overrides
Option values can now be a plain string (existing behavior) or { "value": "...", "overrides": {...} } to override modelOverrides, skip, or toolNameMapping for that specific option combination
Overrides are deep-merged into the framework config during test matrix expansion

Example

{
  "options": {
    "modelSetup": [
      "single",
      {
        "value": "fallback",
        "overrides": {
          "modelOverrides": { "request": "some-other-model" }
        }
      }
    ]
  }
}

The "single" variant uses the framework's default config. The "fallback" variant overrides modelOverrides.request for all checks in that test run.

Motivation
Some framework variants need different validation expectations (e.g., a different expected model name, different checks to skip, or different tool name mappings). Previously this required duplicating the entire framework folder. With option overrides, a single config.json can express variant-specific config inline.

Summary
Add support for object-style option values in framework config.json with per-value config overrides
Option values can now be a plain string (existing behavior) or { "value": "...", "overrides": {...} } to override modelOverrides, skip, or toolNameMapping for that specific option combination
Overrides are deep-merged into the framework config during test matrix expansion
Example

{
  "options": {
    "modelSetup": [
      "single",
      {
        "value": "fallback",
        "overrides": {
          "modelOverrides": { "request": "some-other-model" }
        }
      }
    ]
  }
}
The "single" variant uses the framework's default config. The "fallback" variant overrides modelOverrides.request for all checks in that test run.

Motivation
Some framework variants need different validation expectations (e.g., a different expected model name, different checks to skip, or different tool name mappings). Previously this required duplicating the entire framework folder. With option overrides, a single config.json can express variant-specific config inline.
@constantinius constantinius requested a review from a team March 12, 2026 13:02
id: runId,
index: matrix.length, // Track original order for consistent reporting
framework: {
...framework,
Copy link

Choose a reason for hiding this comment

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

Bug: Option overrides for skip and toolNameMapping are shallow-merged, causing them to completely replace base configurations instead of merging with them.
Severity: MEDIUM

Suggested Fix

Explicitly deep-merge the skip and toolNameMapping properties from optionOverrides into the framework configuration, similar to how modelOverrides is currently handled. This will ensure that nested values from both the base and override configurations are combined correctly.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: src/orchestrator.ts#L667

Potential issue: When applying option-specific overrides to a framework configuration,
the `skip` and `toolNameMapping` properties are shallow-merged via a spread operator.
This is inconsistent with `modelOverrides`, which is explicitly deep-merged. As a
result, if a base framework config and an option override both define `skip` or
`toolNameMapping` objects, the override's object will completely replace the base
object, leading to the loss of pre-existing rules from the base configuration. This
behavior contradicts the documented intent to deep-merge overrides.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

...framework.modelOverrides,
...optionOverrides.modelOverrides,
}
: framework.modelOverrides,
Copy link

Choose a reason for hiding this comment

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

Shallow override of skip and toolNameMapping loses framework config

Medium Severity

The ...optionOverrides spread on the framework object shallow-replaces skip and toolNameMapping, while modelOverrides gets explicit deep-merge treatment. If an option override specifies a partial skip (e.g., only checks), the framework's existing skip.tests entries are silently lost. Similarly, if an override specifies one toolNameMapping entry, all other framework-level tool name mappings disappear. The same shallow-replacement issue exists in getOptionCombinations when combining overrides across multiple option dimensions.

Additional Locations (1)
Fix in Cursor Fix in Web

@github-actions
Copy link

🟡 AI SDK Integration Test Results

Status: 286 tests failing (no regressions)

Summary

Metric main PR Change
Total Tests 530 530
Passed 231 231
Failed 286 286

Test Matrix

Agent Tests

SDK Basic Agent Test Conversation ID Agent Test Long Input Agent Test Tool Call Agent Test Tool Error Agent Test Vision Agent Test
browser/langgraph blk, combinedblk, compiledblk, custom-stateblk, graphblk, langchainstr, combinedstr, compiledstr, custom-statestr, graphstr, langchain blk, combinedblk, compiledblk, custom-stateblk, graphblk, langchainstr, combinedstr, compiledstr, custom-statestr, graphstr, langchain blk, combinedblk, compiledblk, custom-stateblk, graphblk, langchainstr, combinedstr, compiledstr, custom-statestr, graphstr, langchain blk, combinedblk, compiledblk, custom-stateblk, graphblk, langchainstr, combinedstr, compiledstr, custom-statestr, graphstr, langchain blk, combinedblk, compiledblk, custom-stateblk, graphblk, langchainstr, combinedstr, compiledstr, custom-statestr, graphstr, langchain blk, combinedblk, compiledblk, custom-stateblk, graphblk, langchainstr, combinedstr, compiledstr, custom-statestr, graphstr, langchain
cloudflare/langgraph
cloudflare/vercel
nextjs/mastra
nextjs/vercel blkstr blkstr blkstr blkstr blkstr blkstr
node/langgraph
node/manual
node/mastra
node/vercel
php/laravel blkstr blkstr blkstr blkstr blkstr blkstr
python/langgraph as as as as as as
python/manual as as as as as as
python/openai-agents
python/pydantic-ai

Embedding Tests

SDK Basic Embeddings Test
browser/google-genai
browser/langchain
browser/openai
cloudflare/google-genai
cloudflare/langchain
cloudflare/openai
cloudflare/vercel
nextjs/google-genai
nextjs/langchain
nextjs/openai
nextjs/vercel
node/google-genai
node/langchain
node/openai
node/vercel
php/laravel
python/google-genai a, blks, blk
python/langchain a, blks, blk
python/litellm a, blks, blk
python/manual a, blks, blk
python/openai a, blks, blk

LLM Tests

SDK Basic Error LLM Test Basic LLM Test Conversation ID LLM Test Long Input LLM Test Multi-Turn LLM Test Vision LLM Test
browser/anthropic blkstr blkstr blkstr blkstr blkstr blkstr
browser/google-genai blkstr blkstr blkstr blkstr blkstr blkstr
browser/langchain blkstr blkstr blkstr blkstr blkstr blkstr
browser/openai blkstr blkstr blkstr blkstr blkstr blkstr
cloudflare/anthropic blkstr blkstr blkstr blkstr blkstr blkstr
cloudflare/google-genai blkstr blkstr blkstr blkstr blkstr blkstr
cloudflare/langchain blkstr blkstr blkstr blkstr blkstr blkstr
cloudflare/openai blkstr blkstr blkstr blkstr blkstr blkstr
nextjs/anthropic blkstr blkstr blkstr blkstr blkstr blkstr
nextjs/google-genai blkstr blkstr blkstr blkstr blkstr blkstr
nextjs/langchain blkstr blkstr blkstr blkstr blkstr blkstr
nextjs/openai blkstr blkstr blkstr blkstr blkstr blkstr
node/anthropic blkstr blkstr blkstr blkstr blkstr blkstr
node/google-genai blkstr blkstr blkstr blkstr blkstr blkstr
node/langchain blkstr blkstr blkstr blkstr blkstr blkstr
node/manual
node/openai blkstr blkstr blkstr blkstr blkstr blkstr
python/anthropic a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str
python/cohere s, blk, v1s, blk, v2s, str, v1s, str, v2 s, blk, v1s, blk, v2s, str, v1s, str, v2 s, blk, v1s, blk, v2s, str, v1s, str, v2 s, blk, v1s, blk, v2s, str, v1s, str, v2
python/google-genai a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str
python/langchain a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str
python/litellm a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str
python/manual a, blks, blk a, blks, blk a, blks, blk a, blks, blk a, blks, blk
python/openai a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str a, blka, strs, blks, str

Legend: ✅ Pass | ❌ Fail | ✅🔧 Fixed | ❌📉 Regressed | ✅🆕 New (pass) | ❌🆕 New (fail) | 🗑️ Removed | str=streaming blk=blocking a=async s=sync hi=highlevel lo=lowlevel


Generated by AI SDK Integration Tests

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.

1 participant