2026-02-06 18:35:36 -05:00
|
|
|
import {
|
|
|
|
|
supportsAdaptiveThinking,
|
|
|
|
|
bedrockOutputParser,
|
|
|
|
|
bedrockInputParser,
|
|
|
|
|
supportsContext1m,
|
|
|
|
|
} from '../src/bedrock';
|
|
|
|
|
|
|
|
|
|
describe('supportsAdaptiveThinking', () => {
|
|
|
|
|
test('should return true for claude-opus-4-6', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-opus-4-6')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-opus-4.6', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-opus-4.6')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-opus-4-7 (future)', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-opus-4-7')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-opus-5 (future)', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-opus-5')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-opus-9 (future)', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-opus-9')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-sonnet-5 (future)', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-sonnet-5')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-sonnet-6 (future)', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-sonnet-6')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-opus-4-5', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-opus-4-5')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-opus-4', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-opus-4')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-opus-4-0', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-opus-4-0')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-sonnet-4-5', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-sonnet-4-5')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-sonnet-4', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-sonnet-4')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-3-7-sonnet', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-3-7-sonnet')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for unrelated model', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('gpt-4o')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should handle Bedrock model ID with prefix stripping', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('anthropic.claude-opus-4-6-v1:0')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should handle cross-region Bedrock model ID', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('us.anthropic.claude-opus-4-6-v1')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-4-6-opus (alternate naming)', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-4-6-opus')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for anthropic.claude-4-6-opus (alternate naming)', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('anthropic.claude-4-6-opus')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-5-sonnet (alternate naming)', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-5-sonnet')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for anthropic.claude-5-sonnet (alternate naming)', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('anthropic.claude-5-sonnet')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-4-5-opus (alternate naming, below threshold)', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-4-5-opus')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-4-sonnet (alternate naming, below threshold)', () => {
|
|
|
|
|
expect(supportsAdaptiveThinking('claude-4-sonnet')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('supportsContext1m', () => {
|
|
|
|
|
test('should return true for claude-sonnet-4', () => {
|
|
|
|
|
expect(supportsContext1m('claude-sonnet-4')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-sonnet-4-5', () => {
|
|
|
|
|
expect(supportsContext1m('claude-sonnet-4-5')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-sonnet-5 (future)', () => {
|
|
|
|
|
expect(supportsContext1m('claude-sonnet-5')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-opus-4-6', () => {
|
|
|
|
|
expect(supportsContext1m('claude-opus-4-6')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-opus-5 (future)', () => {
|
|
|
|
|
expect(supportsContext1m('claude-opus-5')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-opus-4-5', () => {
|
|
|
|
|
expect(supportsContext1m('claude-opus-4-5')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-opus-4', () => {
|
|
|
|
|
expect(supportsContext1m('claude-opus-4')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-3-7-sonnet', () => {
|
|
|
|
|
expect(supportsContext1m('claude-3-7-sonnet')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-sonnet-3', () => {
|
|
|
|
|
expect(supportsContext1m('claude-sonnet-3')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for unrelated model', () => {
|
|
|
|
|
expect(supportsContext1m('gpt-4o')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-4-sonnet (alternate naming)', () => {
|
|
|
|
|
expect(supportsContext1m('claude-4-sonnet')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-5-sonnet (alternate naming)', () => {
|
|
|
|
|
expect(supportsContext1m('claude-5-sonnet')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return true for claude-4-6-opus (alternate naming)', () => {
|
|
|
|
|
expect(supportsContext1m('claude-4-6-opus')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-3-sonnet (alternate naming, below threshold)', () => {
|
|
|
|
|
expect(supportsContext1m('claude-3-sonnet')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should return false for claude-4-5-opus (alternate naming, below threshold)', () => {
|
|
|
|
|
expect(supportsContext1m('claude-4-5-opus')).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
});
|
2025-05-23 00:42:51 -04:00
|
|
|
|
|
|
|
|
describe('bedrockInputParser', () => {
|
|
|
|
|
describe('Model Matching for Reasoning Configuration', () => {
|
|
|
|
|
test('should match anthropic.claude-3-7-sonnet model', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-3-7-sonnet',
|
|
|
|
|
};
|
2026-02-06 18:35:36 -05:00
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
2025-05-23 00:42:51 -04:00
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toBe(true);
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBe(2000);
|
|
|
|
|
expect(additionalFields.anthropic_beta).toEqual(['output-128k-2025-02-19']);
|
|
|
|
|
});
|
|
|
|
|
|
2026-01-15 22:48:48 -05:00
|
|
|
test('should match anthropic.claude-sonnet-4 model with 1M context header', () => {
|
2025-05-23 00:42:51 -04:00
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-sonnet-4',
|
|
|
|
|
};
|
2026-02-06 18:35:36 -05:00
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
2025-05-23 00:42:51 -04:00
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toBe(true);
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBe(2000);
|
2026-01-15 22:48:48 -05:00
|
|
|
expect(additionalFields.anthropic_beta).toEqual([
|
|
|
|
|
'output-128k-2025-02-19',
|
|
|
|
|
'context-1m-2025-08-07',
|
|
|
|
|
]);
|
2025-05-23 00:42:51 -04:00
|
|
|
});
|
|
|
|
|
|
2026-02-06 18:35:36 -05:00
|
|
|
test('should match anthropic.claude-opus-5 model with adaptive thinking and 1M context', () => {
|
2025-05-23 00:42:51 -04:00
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-opus-5',
|
|
|
|
|
};
|
2026-02-06 18:35:36 -05:00
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
2025-05-23 00:42:51 -04:00
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
2026-02-06 18:35:36 -05:00
|
|
|
expect(additionalFields.thinking).toEqual({ type: 'adaptive' });
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBeUndefined();
|
|
|
|
|
expect(additionalFields.anthropic_beta).toEqual([
|
|
|
|
|
'output-128k-2025-02-19',
|
|
|
|
|
'context-1m-2025-08-07',
|
|
|
|
|
]);
|
2025-05-23 00:42:51 -04:00
|
|
|
});
|
|
|
|
|
|
2026-01-15 22:48:48 -05:00
|
|
|
test('should match anthropic.claude-haiku-6 model without 1M context header', () => {
|
2025-05-23 00:42:51 -04:00
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-haiku-6',
|
|
|
|
|
};
|
2026-02-06 18:35:36 -05:00
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
2025-05-23 00:42:51 -04:00
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toBe(true);
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBe(2000);
|
|
|
|
|
expect(additionalFields.anthropic_beta).toEqual(['output-128k-2025-02-19']);
|
|
|
|
|
});
|
|
|
|
|
|
2026-01-15 22:48:48 -05:00
|
|
|
test('should match anthropic.claude-4-sonnet model with 1M context header', () => {
|
2025-05-23 00:42:51 -04:00
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-4-sonnet',
|
|
|
|
|
};
|
2026-02-06 18:35:36 -05:00
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
2025-05-23 00:42:51 -04:00
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toBe(true);
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBe(2000);
|
2026-01-15 22:48:48 -05:00
|
|
|
expect(additionalFields.anthropic_beta).toEqual([
|
|
|
|
|
'output-128k-2025-02-19',
|
|
|
|
|
'context-1m-2025-08-07',
|
|
|
|
|
]);
|
2025-05-23 00:42:51 -04:00
|
|
|
});
|
|
|
|
|
|
2026-01-15 22:48:48 -05:00
|
|
|
test('should match anthropic.claude-4.5-sonnet model with 1M context header', () => {
|
2025-05-23 00:42:51 -04:00
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-4.5-sonnet',
|
|
|
|
|
};
|
2026-02-06 18:35:36 -05:00
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
2025-05-23 00:42:51 -04:00
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toBe(true);
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBe(2000);
|
2026-01-15 22:48:48 -05:00
|
|
|
expect(additionalFields.anthropic_beta).toEqual([
|
|
|
|
|
'output-128k-2025-02-19',
|
|
|
|
|
'context-1m-2025-08-07',
|
|
|
|
|
]);
|
2025-05-23 00:42:51 -04:00
|
|
|
});
|
|
|
|
|
|
2026-01-15 22:48:48 -05:00
|
|
|
test('should match anthropic.claude-4-7-sonnet model with 1M context header', () => {
|
2025-05-23 00:42:51 -04:00
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-4-7-sonnet',
|
|
|
|
|
};
|
2026-02-06 18:35:36 -05:00
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
2025-05-23 00:42:51 -04:00
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toBe(true);
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBe(2000);
|
2026-01-15 22:48:48 -05:00
|
|
|
expect(additionalFields.anthropic_beta).toEqual([
|
|
|
|
|
'output-128k-2025-02-19',
|
|
|
|
|
'context-1m-2025-08-07',
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should match anthropic.claude-sonnet-4-20250514-v1:0 with full model ID', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-sonnet-4-20250514-v1:0',
|
|
|
|
|
};
|
2026-02-06 18:35:36 -05:00
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
2026-01-15 22:48:48 -05:00
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toBe(true);
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBe(2000);
|
|
|
|
|
expect(additionalFields.anthropic_beta).toEqual([
|
|
|
|
|
'output-128k-2025-02-19',
|
|
|
|
|
'context-1m-2025-08-07',
|
|
|
|
|
]);
|
2025-05-23 00:42:51 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should not match non-Claude models', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'some-other-model',
|
|
|
|
|
};
|
2026-02-06 18:35:36 -05:00
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
2025-05-23 00:42:51 -04:00
|
|
|
expect(result.additionalModelRequestFields).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
2026-01-11 00:56:19 +05:30
|
|
|
test('should not add anthropic_beta to Moonshot Kimi K2 models', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'moonshot.kimi-k2-0711-thinking',
|
|
|
|
|
};
|
2026-02-06 18:35:36 -05:00
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
2026-01-11 00:56:19 +05:30
|
|
|
const additionalFields = result.additionalModelRequestFields as
|
|
|
|
|
| Record<string, unknown>
|
|
|
|
|
| undefined;
|
|
|
|
|
expect(additionalFields?.anthropic_beta).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should not add anthropic_beta to DeepSeek models', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'deepseek.deepseek-r1',
|
|
|
|
|
};
|
2026-02-06 18:35:36 -05:00
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
2026-01-11 00:56:19 +05:30
|
|
|
const additionalFields = result.additionalModelRequestFields as
|
|
|
|
|
| Record<string, unknown>
|
|
|
|
|
| undefined;
|
|
|
|
|
expect(additionalFields?.anthropic_beta).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
2026-01-15 22:48:48 -05:00
|
|
|
test('should respect explicit thinking configuration but still add beta headers', () => {
|
2025-05-23 00:42:51 -04:00
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-sonnet-4',
|
|
|
|
|
thinking: false,
|
|
|
|
|
};
|
2026-02-06 18:35:36 -05:00
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
2025-05-23 00:42:51 -04:00
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toBeUndefined();
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBeUndefined();
|
2026-01-15 22:48:48 -05:00
|
|
|
expect(additionalFields.anthropic_beta).toEqual([
|
|
|
|
|
'output-128k-2025-02-19',
|
|
|
|
|
'context-1m-2025-08-07',
|
|
|
|
|
]);
|
2025-05-23 00:42:51 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should respect custom thinking budget', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-sonnet-4',
|
|
|
|
|
thinking: true,
|
|
|
|
|
thinkingBudget: 3000,
|
|
|
|
|
};
|
2026-02-06 18:35:36 -05:00
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
2025-05-23 00:42:51 -04:00
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toBe(true);
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBe(3000);
|
|
|
|
|
});
|
|
|
|
|
});
|
2026-02-06 18:35:36 -05:00
|
|
|
|
|
|
|
|
describe('Opus 4.6 Adaptive Thinking', () => {
|
|
|
|
|
test('should default to adaptive thinking for anthropic.claude-opus-4-6-v1', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-opus-4-6-v1',
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
|
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toEqual({ type: 'adaptive' });
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBeUndefined();
|
|
|
|
|
expect(additionalFields.anthropic_beta).toEqual([
|
|
|
|
|
'output-128k-2025-02-19',
|
|
|
|
|
'context-1m-2025-08-07',
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should handle cross-region model ID us.anthropic.claude-opus-4-6-v1', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'us.anthropic.claude-opus-4-6-v1',
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
|
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toEqual({ type: 'adaptive' });
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBeUndefined();
|
|
|
|
|
expect(additionalFields.anthropic_beta).toEqual([
|
|
|
|
|
'output-128k-2025-02-19',
|
|
|
|
|
'context-1m-2025-08-07',
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should handle cross-region model ID global.anthropic.claude-opus-4-6-v1', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'global.anthropic.claude-opus-4-6-v1',
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
|
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toEqual({ type: 'adaptive' });
|
|
|
|
|
expect(additionalFields.anthropic_beta).toEqual([
|
|
|
|
|
'output-128k-2025-02-19',
|
|
|
|
|
'context-1m-2025-08-07',
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should pass effort parameter via output_config for adaptive models', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-opus-4-6-v1',
|
|
|
|
|
effort: 'medium',
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
|
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toEqual({ type: 'adaptive' });
|
|
|
|
|
expect(additionalFields.output_config).toEqual({ effort: 'medium' });
|
|
|
|
|
expect(additionalFields.effort).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should not include output_config when effort is unset (empty string)', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-opus-4-6-v1',
|
|
|
|
|
effort: '',
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
|
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toEqual({ type: 'adaptive' });
|
|
|
|
|
expect(additionalFields.output_config).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should respect thinking=false for adaptive models', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-opus-4-6-v1',
|
|
|
|
|
thinking: false,
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
|
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toBeUndefined();
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBeUndefined();
|
|
|
|
|
expect(additionalFields.anthropic_beta).toEqual([
|
|
|
|
|
'output-128k-2025-02-19',
|
|
|
|
|
'context-1m-2025-08-07',
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should preserve effort when thinking=false for adaptive models', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-opus-4-6-v1',
|
|
|
|
|
thinking: false,
|
|
|
|
|
effort: 'high',
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
|
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toBeUndefined();
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBeUndefined();
|
|
|
|
|
expect(additionalFields.output_config).toEqual({ effort: 'high' });
|
|
|
|
|
expect(additionalFields.effort).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should strip effort for non-adaptive thinking models', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-sonnet-4-5-20250929-v1:0',
|
|
|
|
|
effort: 'high',
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
|
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toBe(true);
|
|
|
|
|
expect(additionalFields.thinkingBudget).toBe(2000);
|
|
|
|
|
expect(additionalFields.effort).toBeUndefined();
|
|
|
|
|
expect(additionalFields.output_config).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should not include effort for Opus 4.5 (non-adaptive)', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-opus-4-5-v1:0',
|
|
|
|
|
effort: 'low',
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
|
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toBe(true);
|
|
|
|
|
expect(additionalFields.effort).toBeUndefined();
|
|
|
|
|
expect(additionalFields.output_config).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should support max effort for Opus 4.6', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-opus-4-6-v1',
|
|
|
|
|
effort: 'max',
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
|
|
|
|
const additionalFields = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(additionalFields.thinking).toEqual({ type: 'adaptive' });
|
|
|
|
|
expect(additionalFields.output_config).toEqual({ effort: 'max' });
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('bedrockOutputParser with configureThinking', () => {
|
🆔 fix: Atomic File Dedupe, Bedrock Tokens Fix, and Allowed MIME Types (#11675)
* feat: Add support for Apache Parquet MIME types
- Introduced 'application/x-parquet' to the full MIME types list and code interpreter MIME types list.
- Updated application MIME types regex to include 'x-parquet' and 'vnd.apache.parquet'.
- Added mapping for '.parquet' files to 'application/x-parquet' in code type mapping, enhancing file format support.
* feat: Implement atomic file claiming for code execution outputs
- Added a new `claimCodeFile` function to atomically claim a file_id for code execution outputs, preventing duplicates by using a compound key of filename and conversationId.
- Updated `processCodeOutput` to utilize the new claiming mechanism, ensuring that concurrent calls for the same filename converge on a single record.
- Refactored related tests to validate the new atomic claiming behavior and its impact on file usage tracking and versioning.
* fix: Update image file handling to use cache-busting filepath
- Modified the `processCodeOutput` function to generate a cache-busting filepath for updated image files, improving browser caching behavior.
- Adjusted related tests to reflect the change from versioned filenames to cache-busted filepaths, ensuring accurate validation of image updates.
* fix: Update step handler to prevent undefined content for non-tool call types
- Modified the condition in useStepHandler to ensure that undefined content is only assigned for specific content types, enhancing the robustness of content handling.
* fix: Update bedrockOutputParser to handle maxTokens for adaptive models
- Modified the bedrockOutputParser logic to ensure that maxTokens is not set for adaptive models when neither maxTokens nor maxOutputTokens are provided, improving the handling of adaptive thinking configurations.
- Updated related tests to reflect these changes, ensuring accurate validation of the output for adaptive models.
* chore: Update @librechat/agents to version 3.1.38 in package.json and package-lock.json
* fix: Enhance file claiming and error handling in code processing
- Updated the `processCodeOutput` function to use a consistent file ID for claiming files, preventing duplicates and improving concurrency handling.
- Refactored the `createFileMethods` to include error handling for failed file claims, ensuring robust behavior when claiming files for conversations.
- These changes enhance the reliability of file management in the application.
* fix: Update adaptive thinking test for Opus 4.6 model
- Modified the test for configuring adaptive thinking to reflect that no default maxTokens should be set for the Opus 4.6 model.
- Updated assertions to ensure that maxTokens is undefined, aligning with the expected behavior for adaptive models.
2026-02-07 13:26:18 -05:00
|
|
|
test('should preserve adaptive thinking config without setting default maxTokens', () => {
|
2026-02-06 18:35:36 -05:00
|
|
|
const parsed = bedrockInputParser.parse({
|
|
|
|
|
model: 'anthropic.claude-opus-4-6-v1',
|
|
|
|
|
}) as Record<string, unknown>;
|
|
|
|
|
const output = bedrockOutputParser(parsed as Record<string, unknown>);
|
|
|
|
|
const amrf = output.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(amrf.thinking).toEqual({ type: 'adaptive' });
|
🆔 fix: Atomic File Dedupe, Bedrock Tokens Fix, and Allowed MIME Types (#11675)
* feat: Add support for Apache Parquet MIME types
- Introduced 'application/x-parquet' to the full MIME types list and code interpreter MIME types list.
- Updated application MIME types regex to include 'x-parquet' and 'vnd.apache.parquet'.
- Added mapping for '.parquet' files to 'application/x-parquet' in code type mapping, enhancing file format support.
* feat: Implement atomic file claiming for code execution outputs
- Added a new `claimCodeFile` function to atomically claim a file_id for code execution outputs, preventing duplicates by using a compound key of filename and conversationId.
- Updated `processCodeOutput` to utilize the new claiming mechanism, ensuring that concurrent calls for the same filename converge on a single record.
- Refactored related tests to validate the new atomic claiming behavior and its impact on file usage tracking and versioning.
* fix: Update image file handling to use cache-busting filepath
- Modified the `processCodeOutput` function to generate a cache-busting filepath for updated image files, improving browser caching behavior.
- Adjusted related tests to reflect the change from versioned filenames to cache-busted filepaths, ensuring accurate validation of image updates.
* fix: Update step handler to prevent undefined content for non-tool call types
- Modified the condition in useStepHandler to ensure that undefined content is only assigned for specific content types, enhancing the robustness of content handling.
* fix: Update bedrockOutputParser to handle maxTokens for adaptive models
- Modified the bedrockOutputParser logic to ensure that maxTokens is not set for adaptive models when neither maxTokens nor maxOutputTokens are provided, improving the handling of adaptive thinking configurations.
- Updated related tests to reflect these changes, ensuring accurate validation of the output for adaptive models.
* chore: Update @librechat/agents to version 3.1.38 in package.json and package-lock.json
* fix: Enhance file claiming and error handling in code processing
- Updated the `processCodeOutput` function to use a consistent file ID for claiming files, preventing duplicates and improving concurrency handling.
- Refactored the `createFileMethods` to include error handling for failed file claims, ensuring robust behavior when claiming files for conversations.
- These changes enhance the reliability of file management in the application.
* fix: Update adaptive thinking test for Opus 4.6 model
- Modified the test for configuring adaptive thinking to reflect that no default maxTokens should be set for the Opus 4.6 model.
- Updated assertions to ensure that maxTokens is undefined, aligning with the expected behavior for adaptive models.
2026-02-07 13:26:18 -05:00
|
|
|
expect(output.maxTokens).toBeUndefined();
|
2026-02-06 18:35:36 -05:00
|
|
|
expect(output.maxOutputTokens).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should respect user-provided maxTokens for adaptive model', () => {
|
|
|
|
|
const parsed = bedrockInputParser.parse({
|
|
|
|
|
model: 'anthropic.claude-opus-4-6-v1',
|
|
|
|
|
maxTokens: 32000,
|
|
|
|
|
}) as Record<string, unknown>;
|
|
|
|
|
const output = bedrockOutputParser(parsed as Record<string, unknown>);
|
|
|
|
|
expect(output.maxTokens).toBe(32000);
|
|
|
|
|
});
|
|
|
|
|
|
🆔 fix: Atomic File Dedupe, Bedrock Tokens Fix, and Allowed MIME Types (#11675)
* feat: Add support for Apache Parquet MIME types
- Introduced 'application/x-parquet' to the full MIME types list and code interpreter MIME types list.
- Updated application MIME types regex to include 'x-parquet' and 'vnd.apache.parquet'.
- Added mapping for '.parquet' files to 'application/x-parquet' in code type mapping, enhancing file format support.
* feat: Implement atomic file claiming for code execution outputs
- Added a new `claimCodeFile` function to atomically claim a file_id for code execution outputs, preventing duplicates by using a compound key of filename and conversationId.
- Updated `processCodeOutput` to utilize the new claiming mechanism, ensuring that concurrent calls for the same filename converge on a single record.
- Refactored related tests to validate the new atomic claiming behavior and its impact on file usage tracking and versioning.
* fix: Update image file handling to use cache-busting filepath
- Modified the `processCodeOutput` function to generate a cache-busting filepath for updated image files, improving browser caching behavior.
- Adjusted related tests to reflect the change from versioned filenames to cache-busted filepaths, ensuring accurate validation of image updates.
* fix: Update step handler to prevent undefined content for non-tool call types
- Modified the condition in useStepHandler to ensure that undefined content is only assigned for specific content types, enhancing the robustness of content handling.
* fix: Update bedrockOutputParser to handle maxTokens for adaptive models
- Modified the bedrockOutputParser logic to ensure that maxTokens is not set for adaptive models when neither maxTokens nor maxOutputTokens are provided, improving the handling of adaptive thinking configurations.
- Updated related tests to reflect these changes, ensuring accurate validation of the output for adaptive models.
* chore: Update @librechat/agents to version 3.1.38 in package.json and package-lock.json
* fix: Enhance file claiming and error handling in code processing
- Updated the `processCodeOutput` function to use a consistent file ID for claiming files, preventing duplicates and improving concurrency handling.
- Refactored the `createFileMethods` to include error handling for failed file claims, ensuring robust behavior when claiming files for conversations.
- These changes enhance the reliability of file management in the application.
* fix: Update adaptive thinking test for Opus 4.6 model
- Modified the test for configuring adaptive thinking to reflect that no default maxTokens should be set for the Opus 4.6 model.
- Updated assertions to ensure that maxTokens is undefined, aligning with the expected behavior for adaptive models.
2026-02-07 13:26:18 -05:00
|
|
|
test('should use maxOutputTokens as maxTokens for adaptive model when maxTokens is not set', () => {
|
|
|
|
|
const parsed = bedrockInputParser.parse({
|
|
|
|
|
model: 'anthropic.claude-opus-4-6-v1',
|
|
|
|
|
maxOutputTokens: 24000,
|
|
|
|
|
}) as Record<string, unknown>;
|
|
|
|
|
const output = bedrockOutputParser(parsed as Record<string, unknown>);
|
|
|
|
|
expect(output.maxTokens).toBe(24000);
|
|
|
|
|
expect(output.maxOutputTokens).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
2026-02-06 18:35:36 -05:00
|
|
|
test('should convert thinking=true to enabled config for non-adaptive models', () => {
|
|
|
|
|
const parsed = bedrockInputParser.parse({
|
|
|
|
|
model: 'anthropic.claude-sonnet-4-5-20250929-v1:0',
|
|
|
|
|
}) as Record<string, unknown>;
|
|
|
|
|
const output = bedrockOutputParser(parsed as Record<string, unknown>);
|
|
|
|
|
const amrf = output.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(amrf.thinking).toEqual({ type: 'enabled', budget_tokens: 2000 });
|
|
|
|
|
expect(output.maxTokens).toBe(8192);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should pass output_config through for adaptive model with effort', () => {
|
|
|
|
|
const parsed = bedrockInputParser.parse({
|
|
|
|
|
model: 'anthropic.claude-opus-4-6-v1',
|
|
|
|
|
effort: 'low',
|
|
|
|
|
}) as Record<string, unknown>;
|
|
|
|
|
const output = bedrockOutputParser(parsed as Record<string, unknown>);
|
|
|
|
|
const amrf = output.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(amrf.thinking).toEqual({ type: 'adaptive' });
|
|
|
|
|
expect(amrf.output_config).toEqual({ effort: 'low' });
|
|
|
|
|
});
|
|
|
|
|
|
🆔 fix: Atomic File Dedupe, Bedrock Tokens Fix, and Allowed MIME Types (#11675)
* feat: Add support for Apache Parquet MIME types
- Introduced 'application/x-parquet' to the full MIME types list and code interpreter MIME types list.
- Updated application MIME types regex to include 'x-parquet' and 'vnd.apache.parquet'.
- Added mapping for '.parquet' files to 'application/x-parquet' in code type mapping, enhancing file format support.
* feat: Implement atomic file claiming for code execution outputs
- Added a new `claimCodeFile` function to atomically claim a file_id for code execution outputs, preventing duplicates by using a compound key of filename and conversationId.
- Updated `processCodeOutput` to utilize the new claiming mechanism, ensuring that concurrent calls for the same filename converge on a single record.
- Refactored related tests to validate the new atomic claiming behavior and its impact on file usage tracking and versioning.
* fix: Update image file handling to use cache-busting filepath
- Modified the `processCodeOutput` function to generate a cache-busting filepath for updated image files, improving browser caching behavior.
- Adjusted related tests to reflect the change from versioned filenames to cache-busted filepaths, ensuring accurate validation of image updates.
* fix: Update step handler to prevent undefined content for non-tool call types
- Modified the condition in useStepHandler to ensure that undefined content is only assigned for specific content types, enhancing the robustness of content handling.
* fix: Update bedrockOutputParser to handle maxTokens for adaptive models
- Modified the bedrockOutputParser logic to ensure that maxTokens is not set for adaptive models when neither maxTokens nor maxOutputTokens are provided, improving the handling of adaptive thinking configurations.
- Updated related tests to reflect these changes, ensuring accurate validation of the output for adaptive models.
* chore: Update @librechat/agents to version 3.1.38 in package.json and package-lock.json
* fix: Enhance file claiming and error handling in code processing
- Updated the `processCodeOutput` function to use a consistent file ID for claiming files, preventing duplicates and improving concurrency handling.
- Refactored the `createFileMethods` to include error handling for failed file claims, ensuring robust behavior when claiming files for conversations.
- These changes enhance the reliability of file management in the application.
* fix: Update adaptive thinking test for Opus 4.6 model
- Modified the test for configuring adaptive thinking to reflect that no default maxTokens should be set for the Opus 4.6 model.
- Updated assertions to ensure that maxTokens is undefined, aligning with the expected behavior for adaptive models.
2026-02-07 13:26:18 -05:00
|
|
|
test('should not set maxTokens for adaptive models when neither maxTokens nor maxOutputTokens are provided', () => {
|
2026-02-06 18:35:36 -05:00
|
|
|
const parsed = bedrockInputParser.parse({
|
|
|
|
|
model: 'anthropic.claude-opus-4-6-v1',
|
|
|
|
|
}) as Record<string, unknown>;
|
|
|
|
|
parsed.maxOutputTokens = undefined;
|
|
|
|
|
(parsed as Record<string, unknown>).maxTokens = undefined;
|
|
|
|
|
const output = bedrockOutputParser(parsed as Record<string, unknown>);
|
🆔 fix: Atomic File Dedupe, Bedrock Tokens Fix, and Allowed MIME Types (#11675)
* feat: Add support for Apache Parquet MIME types
- Introduced 'application/x-parquet' to the full MIME types list and code interpreter MIME types list.
- Updated application MIME types regex to include 'x-parquet' and 'vnd.apache.parquet'.
- Added mapping for '.parquet' files to 'application/x-parquet' in code type mapping, enhancing file format support.
* feat: Implement atomic file claiming for code execution outputs
- Added a new `claimCodeFile` function to atomically claim a file_id for code execution outputs, preventing duplicates by using a compound key of filename and conversationId.
- Updated `processCodeOutput` to utilize the new claiming mechanism, ensuring that concurrent calls for the same filename converge on a single record.
- Refactored related tests to validate the new atomic claiming behavior and its impact on file usage tracking and versioning.
* fix: Update image file handling to use cache-busting filepath
- Modified the `processCodeOutput` function to generate a cache-busting filepath for updated image files, improving browser caching behavior.
- Adjusted related tests to reflect the change from versioned filenames to cache-busted filepaths, ensuring accurate validation of image updates.
* fix: Update step handler to prevent undefined content for non-tool call types
- Modified the condition in useStepHandler to ensure that undefined content is only assigned for specific content types, enhancing the robustness of content handling.
* fix: Update bedrockOutputParser to handle maxTokens for adaptive models
- Modified the bedrockOutputParser logic to ensure that maxTokens is not set for adaptive models when neither maxTokens nor maxOutputTokens are provided, improving the handling of adaptive thinking configurations.
- Updated related tests to reflect these changes, ensuring accurate validation of the output for adaptive models.
* chore: Update @librechat/agents to version 3.1.38 in package.json and package-lock.json
* fix: Enhance file claiming and error handling in code processing
- Updated the `processCodeOutput` function to use a consistent file ID for claiming files, preventing duplicates and improving concurrency handling.
- Refactored the `createFileMethods` to include error handling for failed file claims, ensuring robust behavior when claiming files for conversations.
- These changes enhance the reliability of file management in the application.
* fix: Update adaptive thinking test for Opus 4.6 model
- Modified the test for configuring adaptive thinking to reflect that no default maxTokens should be set for the Opus 4.6 model.
- Updated assertions to ensure that maxTokens is undefined, aligning with the expected behavior for adaptive models.
2026-02-07 13:26:18 -05:00
|
|
|
expect(output.maxTokens).toBeUndefined();
|
2026-02-06 18:35:36 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should use enabled default maxTokens (8192) for non-adaptive thinking models', () => {
|
|
|
|
|
const parsed = bedrockInputParser.parse({
|
|
|
|
|
model: 'anthropic.claude-sonnet-4-5-20250929-v1:0',
|
|
|
|
|
}) as Record<string, unknown>;
|
|
|
|
|
parsed.maxOutputTokens = undefined;
|
|
|
|
|
(parsed as Record<string, unknown>).maxTokens = undefined;
|
|
|
|
|
const output = bedrockOutputParser(parsed as Record<string, unknown>);
|
|
|
|
|
expect(output.maxTokens).toBe(8192);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should use default thinking budget (2000) when no custom budget is set', () => {
|
|
|
|
|
const parsed = bedrockInputParser.parse({
|
|
|
|
|
model: 'anthropic.claude-3-7-sonnet',
|
|
|
|
|
}) as Record<string, unknown>;
|
|
|
|
|
const output = bedrockOutputParser(parsed as Record<string, unknown>);
|
|
|
|
|
const amrf = output.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
const thinking = amrf.thinking as { type: string; budget_tokens: number };
|
|
|
|
|
expect(thinking.budget_tokens).toBe(2000);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should override default thinking budget with custom value', () => {
|
|
|
|
|
const parsed = bedrockInputParser.parse({
|
|
|
|
|
model: 'anthropic.claude-3-7-sonnet',
|
|
|
|
|
thinkingBudget: 5000,
|
|
|
|
|
maxTokens: 8192,
|
|
|
|
|
}) as Record<string, unknown>;
|
|
|
|
|
const output = bedrockOutputParser(parsed as Record<string, unknown>);
|
|
|
|
|
const amrf = output.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
const thinking = amrf.thinking as { type: string; budget_tokens: number };
|
|
|
|
|
expect(thinking.budget_tokens).toBe(5000);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should remove additionalModelRequestFields when thinking disabled and no other fields', () => {
|
|
|
|
|
const parsed = bedrockInputParser.parse({
|
|
|
|
|
model: 'some-other-model',
|
|
|
|
|
}) as Record<string, unknown>;
|
|
|
|
|
const output = bedrockOutputParser(parsed as Record<string, unknown>);
|
|
|
|
|
expect(output.additionalModelRequestFields).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('Model switching cleanup', () => {
|
|
|
|
|
test('should strip anthropic_beta when switching from Anthropic to non-Anthropic model', () => {
|
|
|
|
|
const staleConversationData = {
|
|
|
|
|
model: 'openai.gpt-oss-120b-1:0',
|
|
|
|
|
promptCache: true,
|
|
|
|
|
additionalModelRequestFields: {
|
|
|
|
|
anthropic_beta: ['output-128k-2025-02-19', 'context-1m-2025-08-07'],
|
|
|
|
|
thinking: { type: 'adaptive' },
|
|
|
|
|
output_config: { effort: 'high' },
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(staleConversationData) as Record<string, unknown>;
|
|
|
|
|
const amrf = result.additionalModelRequestFields as Record<string, unknown> | undefined;
|
|
|
|
|
expect(amrf?.anthropic_beta).toBeUndefined();
|
|
|
|
|
expect(amrf?.thinking).toBeUndefined();
|
|
|
|
|
expect(amrf?.output_config).toBeUndefined();
|
|
|
|
|
expect(result.promptCache).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should strip promptCache when switching from Claude to non-Claude/Nova model', () => {
|
|
|
|
|
const staleConversationData = {
|
|
|
|
|
model: 'deepseek.deepseek-r1',
|
|
|
|
|
promptCache: true,
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(staleConversationData) as Record<string, unknown>;
|
|
|
|
|
expect(result.promptCache).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should preserve promptCache for Claude models', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-sonnet-4-20250514-v1:0',
|
|
|
|
|
promptCache: true,
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
|
|
|
|
expect(result.promptCache).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should preserve promptCache for Nova models', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'amazon.nova-pro-v1:0',
|
|
|
|
|
promptCache: true,
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
|
|
|
|
expect(result.promptCache).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should strip stale thinking config from additionalModelRequestFields for non-Anthropic models', () => {
|
|
|
|
|
const staleConversationData = {
|
|
|
|
|
model: 'moonshot.kimi-k2-0711-thinking',
|
|
|
|
|
additionalModelRequestFields: {
|
|
|
|
|
thinking: { type: 'enabled', budget_tokens: 2000 },
|
|
|
|
|
thinkingBudget: 2000,
|
|
|
|
|
anthropic_beta: ['output-128k-2025-02-19'],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(staleConversationData) as Record<string, unknown>;
|
|
|
|
|
const amrf = result.additionalModelRequestFields as Record<string, unknown> | undefined;
|
|
|
|
|
expect(amrf?.anthropic_beta).toBeUndefined();
|
|
|
|
|
expect(amrf?.thinking).toBeUndefined();
|
|
|
|
|
expect(amrf?.thinkingBudget).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should not strip anthropic_beta when staying on an Anthropic model', () => {
|
|
|
|
|
const input = {
|
|
|
|
|
model: 'anthropic.claude-opus-4-6-v1',
|
|
|
|
|
};
|
|
|
|
|
const result = bedrockInputParser.parse(input) as Record<string, unknown>;
|
|
|
|
|
const amrf = result.additionalModelRequestFields as Record<string, unknown>;
|
|
|
|
|
expect(amrf.anthropic_beta).toBeDefined();
|
|
|
|
|
expect(Array.isArray(amrf.anthropic_beta)).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
});
|
2025-05-23 00:42:51 -04:00
|
|
|
});
|