Files
OmniRoute/docs/combo-context-requirements.md
Diego Rodrigues de Sa e Souza 04683029a6 fix(build): exec native esbuild binary directly in prepublish (dast-smoke base-red) (#9558)
* fix(build): exec native tool binaries directly in runBuildTool

#8858 routed every resolved local bin through process.execPath to avoid
Windows .cmd shims — but esbuild >=0.25 ships bin/esbuild as the NATIVE
platform executable (ELF on Linux), so Node parsed machine code as JS and
build:cli died with 'SyntaxError: Invalid or unexpected token', turning
dast-smoke red for every PR.

runBuildTool now sniffs the entry's magic bytes (ELF / Mach-O / PE) and
execs native binaries directly; JS entries keep going through this Node
binary (the .cmd-shim avoidance #8858 wanted).

Validation (RED->GREEN on this box):
- RED: node node_modules/esbuild/bin/esbuild --version -> SyntaxError (ELF)
- GREEN: the exact failing CI step reproduced via the new logic bundles
  open-sse/mcp-server/server.ts successfully (4.2MB output, 1.3s).

* fix(docs): add MDX frontmatter to the 20 remaining docs without it

Same failure class as AGENTROUTER_WAF (#9503) and DOCKER_RELEASE_CHANNELS
(this run's dast-smoke red): any doc without frontmatter breaks the
fumadocs MDX loader during next build, killing build:cli/dast-smoke for
every PR. Swept ALL of docs/ (i18n mirrors excluded) in one pass so this
class cannot recur one file at a time.

* docs(env): document OMNIROUTE_INTERNAL_SERVICE_TOKEN(+_FILE), OPENROUTER_PROVIDER_STATS_* and embedded-Redis binding vars

Pre-existing env/docs contract drift from recently merged features made
check:env-doc-sync red for any docs-touching PR. Values and defaults read
from the defining modules (internalServiceAuth.ts, openrouterProviderStats.ts).

* fix(build): resolve bundled npm-cli.js in the standard Unix layout + safe npm fallback off-Windows

The opencode-plugin step hard-failed on GitHub runners because
resolveBundledNpmEntry only looked next to the node binary (Windows zip
layout); hostedtoolcache Node keeps npm at <prefix>/lib/node_modules/npm.
Added that candidate, and when neither exists on non-Windows the step now
falls back to plain 'npm' — the .cmd-shim hazard #8858 avoids is
Windows-only.

* test(mutation): register xai-agent-tools-passthrough.test.ts in stryker tap.testFiles

The test landed on release/v3.8.50 covering
open-sse/handlers/chatCore/passthroughHelpers.ts without the stryker
registration, so Fast Quality Gates' drift detection reds any PR that
carries it. Mechanical registration so its mutant kills count.

---------

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
2026-08-06 02:19:57 -03:00

274 lines
7.2 KiB
Markdown

---
title: "Combo Context Requirements Feature"
version: 3.8.50
lastUpdated: 2026-08-06
---
# Combo Context Requirements Feature
## Overview
The Context Requirements feature allows combo configurations to filter and sort targets based on their context window size. This is useful for use cases requiring large context windows like:
- Long document processing (100k+ tokens)
- Large codebase analysis
- Extensive conversation histories
- Multi-file code reviews
## Configuration
### Schema
Add `contextRequirements` to your combo's runtime config:
```json
{
"contextRequirements": {
"minContextWindow": 128000,
"preferLargeContext": true,
"contextFilterMode": "strict"
}
}
```
### Fields
#### `minContextWindow` (optional)
- **Type**: `number` (0 to 10,000,000)
- **Default**: `undefined` (no filtering)
- **Description**: Filters out models with context windows below this threshold
**Examples**:
- `32000` - Filter out models with <32K context
- `128000` - Require 128K+ context (GPT-4 Turbo, Claude 3)
- `200000` - Require 200K+ context (Claude 3 Opus)
- `1000000` - Require 1M+ context (Gemini 1.5 Pro)
#### `preferLargeContext` (optional)
- **Type**: `boolean`
- **Default**: `false`
- **Description**: When `true`, sorts remaining targets by context size (descending). Large context models are tried first.
#### `contextFilterMode` (optional)
- **Type**: `"strict"` | `"lenient"`
- **Default**: `"lenient"`
- **Description**: How to handle models with unknown context window limits
- `"strict"`: Excludes models with unknown context limits when a known-good target remains; fail-opens to unknowns if the pool would otherwise be empty (#8786)
- `"lenient"`: Includes models with unknown context limits
## Behavior
### Filtering Pipeline
Context requirements are applied after `filterTargetsByRequestCompatibility()`:
1. **Request compatibility filtering** - Removes models incompatible with request (tools, vision, structured output)
2. **Context requirements filtering** - Applies `minContextWindow` and `contextFilterMode`
3. **Context-based sorting** - If `preferLargeContext` is true, sorts by context size descending
### Filter Mode Logic
When `minContextWindow` is set:
**Lenient mode** (default):
- ✅ Includes models with context >= minContextWindow
- ✅ Includes models with unknown context limits
- ❌ Excludes models with context < minContextWindow
**Strict mode**:
- ✅ Includes models with context >= minContextWindow
- ❌ Excludes models with unknown context limits (when at least one known-good target remains)
- ❌ Excludes models with context < minContextWindow
- ⚠️ **Fail-open (#8786)**: if strict filtering would empty the pool and at least one
unknown-context target exists, those unknowns are restored instead of returning
`404 Combo has no executable targets`. Known-too-small targets are never resurrected.
When the pool is still empty (every known target is below `minContextWindow`), the
API returns `terminalReason: "context_requirements_exhausted"` with a recovery hint.
### Sorting Logic
When `preferLargeContext` is true:
- Models are sorted by context window size (descending)
- Unknown context models sort to the end
- Original strategy order is used as a tiebreaker
## Use Cases
### Example 1: Long Document Processing
```json
{
"name": "Document Analysis",
"strategy": "fusion",
"config": {
"contextRequirements": {
"minContextWindow": 128000,
"preferLargeContext": true,
"contextFilterMode": "strict"
}
}
}
```
This configuration:
- Requires 128K+ context window
- Prefers larger context models (Gemini 1.5 Pro > Claude 3 Opus > GPT-4 Turbo)
- Excludes models with unknown context limits
### Example 2: Large Codebase Analysis
```json
{
"name": "Code Review",
"strategy": "auto",
"config": {
"contextRequirements": {
"minContextWindow": 200000,
"preferLargeContext": true,
"contextFilterMode": "lenient"
}
}
}
```
This configuration:
- Requires 200K+ context window
- Prefers larger context models
- Includes models with unknown limits (lenient)
### Example 3: Prefer Large Context Without Strict Requirements
```json
{
"name": "Flexible Chat",
"strategy": "weighted",
"config": {
"contextRequirements": {
"preferLargeContext": true
}
}
}
```
This configuration:
- No minimum requirement (all models eligible)
- Sorts by context size (largest first)
- Useful when large context is preferred but not required
## API Response
When context requirements filter targets, the combo logger outputs:
```
[COMBO] Context requirements: filtered 10 → 3 targets (minContextWindow: 128000, mode: strict)
[COMBO] Context requirements: kept models gemini-1.5-pro, claude-3-opus-20240229, gpt-4-turbo
[COMBO] Context requirements: sorted by context size (descending): gemini-1.5-pro(1000000), claude-3-opus-20240229(200000), gpt-4-turbo(128000)
```
## Implementation Details
### Backend Module
`open-sse/services/combo/contextRequirements.ts`:
- `applyContextRequirements()` - Main filtering function
- `getTargetContextWindow()` - Context lookup helper
- Uses `getModelContextLimit()` from `modelCapabilities.ts`
### Integration Point
`open-sse/services/combo.ts` line 1187:
```typescript
orderedTargets = filterTargetsByRequestCompatibility(orderedTargets, body, log);
orderedTargets = applyContextRequirements(orderedTargets, config.contextRequirements, log);
```
### Schema Definition
`src/shared/validation/schemas/combo.ts`:
```typescript
contextRequirements: z
.object({
minContextWindow: z.coerce.number().int().min(0).max(10_000_000).optional(),
preferLargeContext: z.boolean().optional(),
contextFilterMode: z.enum(["strict", "lenient"]).optional(),
})
.strict()
.optional(),
```
## Testing
### Run Tests
```bash
# Unit tests (schema + logic)
npm test tests/unit/combo-context-requirements.test.ts
# Integration tests (end-to-end)
npm test tests/unit/combo/context-requirements-integration.test.ts
```
### Test Coverage
- Schema validation: 6 tests
- Filtering logic: 6 tests
- Integration: 5 tests
- **Total**: 17/17 passing ✅
## Troubleshooting
### All targets filtered out
**Problem**: All targets removed, combo returns "no compatible models"
**Solutions**:
1. Lower `minContextWindow` threshold
2. Switch to `"lenient"` mode to include unknown context models
3. Remove `minContextWindow` and use only `preferLargeContext`
### Unknown context models excluded
**Problem**: Custom/new models excluded even though they have large context
**Solutions**:
1. Switch to `"lenient"` mode (default)
2. Add model context limit to `modelCapabilities.ts`
3. Remove context filtering and rely on strategy order
### Sorting not applied
**Problem**: `preferLargeContext` doesn't change order
**Check**:
1. Verify `preferLargeContext: true` in config
2. Check if all targets have unknown context (all sort equal)
3. Verify multiple targets remain after filtering
## Related
- [Auto-Combo Routing Strategies](./routing/AUTO-COMBO.md)
- [Resilience Guide](./architecture/RESILIENCE_GUIDE.md)
## Version History
- **v3.8.47**: Initial implementation
- Added `contextRequirements` config
- Created backend filtering module
- Full test coverage (no dedicated dashboard UI yet — configure via combo JSON)