chat
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Viewing readonly version of main branch: v106View latest version
This system handles the "whack-a-mole" problem where different AI models/providers require different parameter formats.
Different models have different requirements:
- Qwen3-32B:
reasoning_effortmust be'none'or'default' - OpenAI o1/o3:
reasoning_effortcan be'low','medium','high' - Anthropic: Uses
extended_thinkingbudget tokens instead - Some models: Don't support certain parameters at all
In model-configs.ts, SelectParameters can define an apiMapping to translate UI values to API values:
{
key: 'reasoningEffort',
label: 'Reasoning Effort',
type: 'select',
options: [
{ value: 'none', label: 'None' },
{ value: 'default', label: 'Default' }
],
default: 'default',
apiMapping: {
'none': 'none',
'default': 'default',
// Backwards compatibility
'low': 'none',
'medium': 'default',
'high': 'default'
}
}
The transformParametersForAPI() function automatically applies these mappings:
import { transformParametersForAPI } from "./model-configs.ts";
// Transform before sending to API
const transformedParams = transformParametersForAPI(model, {
reasoningEffort: 'medium', // UI value
webSearch: true,
});
// Result: { reasoningEffort: 'default', webSearch: true }
The validateParameters() function checks if parameters are valid:
import { validateParameters } from "./model-configs.ts";
const errors = validateParameters(modelId, params);
if (errors.length > 0) {
console.error("Validation errors:", errors);
}
// In complete() or stream() method:
const transformedParams = transformParametersForAPI(model, {
reasoningEffort: options?.reasoningEffort,
imageDetail: options?.imageDetail,
webSearch: options?.webSearch,
codeExecution: options?.codeExecution,
});
// Only add parameters if model supports them AND they're defined
if (transformedParams.reasoningEffort && modelSupportsParameter(model, 'reasoningEffort')) {
requestBody.reasoning_effort = transformedParams.reasoningEffort;
}
{
id: 'custom-model',
name: 'Custom Model',
provider: 'custom',
parameters: [
{
key: 'thinkingLevel',
label: 'Thinking Level',
type: 'select',
options: [
{ value: 'fast', label: 'Fast' },
{ value: 'balanced', label: 'Balanced' },
{ value: 'deep', label: 'Deep' }
],
default: 'balanced',
// Map to what the API actually expects
apiMapping: {
'fast': '1',
'balanced': '2',
'deep': '3'
}
}
],
// Optional: Custom transformation logic
transformParameters: (params) => {
const transformed = { ...params };
// Custom logic here
if (params.special_feature) {
transformed.enable_experimental = true;
}
return transformed;
}
}
- Single Source of Truth: Model configs define both UI and API requirements
- Backwards Compatibility: Old parameter values can be mapped to new ones
- Type Safety: TypeScript ensures parameters are validated at compile time
- Easy Debugging: Clear error messages when parameters don't match
- Extensible: Add new parameter types and transformations easily
To test parameter validation:
import { validateParameters, transformParametersForAPI } from "./model-configs.ts";
// Test validation
const errors = validateParameters('qwen/qwen3-32b', {
reasoningEffort: 'medium', // Valid (will be mapped)
temperature: 0.7,
});
console.log("Validation errors:", errors); // Should be empty
// Test transformation
const transformed = transformParametersForAPI('qwen/qwen3-32b', {
reasoningEffort: 'medium',
});
console.log("Transformed:", transformed); // { reasoningEffort: 'default' }
- Check your model's API documentation
- Find any parameters with specific value requirements
- Add
apiMappingto those parameters inmodel-configs.ts - Update provider to use
transformParametersForAPI()
- Define parameter configs in
model-configs.ts - Use
transformParametersForAPI()before building request body - Use
modelSupportsParameter()to check if parameter is supported - Optionally add validation before making API calls
const transformed = transformParametersForAPI(model, {
reasoningEffort: options?.reasoningEffort,
});
if (transformed.reasoningEffort && modelSupportsParameter(model, 'reasoningEffort')) {
requestBody.reasoning_effort = transformed.reasoningEffort;
}
const errors = validateParameters(modelId, params);
if (errors.length > 0) {
throw new Error(`Invalid parameters: ${errors.join(', ')}`);
}
const transformed = transformParametersForAPI(model, {
reasoningEffort: options?.reasoningEffort ?? 'medium', // UI default
});
// Will automatically map 'medium' to API value