Give the model parameters the same treatment a node's own panel gives them
The picker for a simulator or a judge and a node's parameter panel are the same dialog component, and the dialog has always known how to offer "Use default" on an optional field - showUseDefault, the "Using the default" hint, the reset. It reads one flag, defaultsWhenEmpty, which the node panels set on every optional field and this hand-written list never set at all. So a temperature typed here by mistake had no way back to unset: clearing the box by hand looks the same as never having decided. Set it on all five, and brought the rest of each field in line with what the schema-driven panel produces for the same object: an arrow step a decimal can actually move by, an integer step on the integers, and the tips ModelParameters itself declares, so the same explanation appears in both places. Temperature's max was 2 here and is 1.0 on the server, which has a comment explaining why - the dialog was offering a value the run would be rejected for. Still hand-written rather than derived from the published schema: this dialog picks a model for a run, not a node's configuration, and reaching for a block type's schema to render five known fields would buy a network call and a way to fail. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
984af08f36
commit
074c8fb763
|
|
@ -46,6 +46,25 @@ describe('openLLMDescriptorSettings', () => {
|
|||
expect(chosen).toEqual({ provider: 'InternalOllama', model: 'llama3', parameters: { seed: 7 } });
|
||||
});
|
||||
|
||||
it('offers the same treatment a node parameter panel gives these fields', async () => {
|
||||
const { service, open } = dialog(null);
|
||||
|
||||
await openLLMDescriptorSettings(service, retriever(), { title: 'Simulation Settings' });
|
||||
|
||||
const fields: Array<Record<string, unknown>> = open.mock.calls[0][0].fields;
|
||||
const parameters = fields.filter((field) => field['group'] === 'Model parameters');
|
||||
expect(parameters.map((field) => field['key']))
|
||||
.toEqual(['temperature', 'topP', 'topK', 'maxTokens', 'seed']);
|
||||
// Every one of them is optional, so every one of them can be put back to unset - which a
|
||||
// filled box cannot express on its own, and which the node panels have always offered.
|
||||
expect(parameters.every((field) => field['defaultsWhenEmpty'] === true)).toBe(true);
|
||||
// The bound the server actually enforces on temperature, not the 2 this dialog used to allow.
|
||||
expect(parameters.find((field) => field['key'] === 'temperature')).toMatchObject({ min: 0, max: 1 });
|
||||
// A decimal's arrows have somewhere sensible to go instead of jumping between the two ends.
|
||||
expect(parameters.find((field) => field['key'] === 'topP')?.['stepIncrement']).toBe(0.1);
|
||||
expect(parameters.find((field) => field['key'] === 'topK')?.['step']).toBe(1);
|
||||
});
|
||||
|
||||
it('shows an inherited parameter outside the collapsed section, where it can be seen', async () => {
|
||||
const { service, open } = dialog(null);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,18 +14,48 @@ const PARAMETER_GROUP = 'Model parameters';
|
|||
* The optional sampling knobs, behind a section that starts closed. Provider and model are what
|
||||
* anyone opening this dialog came for; these are for the runs where you already know you want
|
||||
* them, and shown flat they made the common case look like a five-field form.
|
||||
*
|
||||
* <p>These are the same five fields a node's own parameter panel shows, and they are declared to
|
||||
* behave the same way: `defaultsWhenEmpty` so an empty box reads as "the provider decides" and
|
||||
* there is a way back to it after typing, the bounds the server actually enforces, and an arrow
|
||||
* step a decimal can move by. Hand-written rather than derived from the published schema the way
|
||||
* `buildSchemaObjectDialog` does it: this dialog is picking a model for a run, not editing a node's
|
||||
* configuration, and reaching for a block type's schema to render five known fields would buy a
|
||||
* network call and a failure mode. The labels, tips and bounds are ModelParameters' own - keep them
|
||||
* in step with it.
|
||||
*/
|
||||
const PARAMETER_FIELDS: NodeSettingField[] = [
|
||||
{ key: 'temperature', label: 'Temperature', type: 'number', min: 0, max: 2, group: PARAMETER_GROUP,
|
||||
placeholder: 'Leave empty for the default', tip: '0 makes the run as repeatable as the model allows' },
|
||||
{ key: 'topP', label: 'Top P', type: 'number', min: 0, max: 1, group: PARAMETER_GROUP,
|
||||
placeholder: 'Leave empty for the default' },
|
||||
{ key: 'topK', label: 'Top K', type: 'number', min: 1, group: PARAMETER_GROUP,
|
||||
placeholder: 'Leave empty for the default' },
|
||||
{ key: 'maxTokens', label: 'Max tokens', type: 'number', min: 1, group: PARAMETER_GROUP,
|
||||
placeholder: 'Leave empty for the default' },
|
||||
{ key: 'seed', label: 'Seed', type: 'number', group: PARAMETER_GROUP,
|
||||
placeholder: 'Leave empty for the default', tip: 'Fixes the randomness, so two runs can be compared' }
|
||||
{
|
||||
key: 'temperature', label: 'Temperature', type: 'number', group: PARAMETER_GROUP,
|
||||
// The server caps this at 1.0; offering 2 here only produced a value it would reject.
|
||||
min: 0, max: 1, stepIncrement: 0.1,
|
||||
defaultsWhenEmpty: true, placeholder: 'Leave empty for the default',
|
||||
tip: 'Higher values make the output more varied. 0 makes it as repeatable as the model allows.'
|
||||
},
|
||||
{
|
||||
key: 'topP', label: 'Top P', type: 'number', group: PARAMETER_GROUP,
|
||||
min: 0, max: 1, stepIncrement: 0.1,
|
||||
defaultsWhenEmpty: true, placeholder: 'Leave empty for the default',
|
||||
tip: 'Nucleus sampling: consider only the most likely tokens adding up to this probability.'
|
||||
},
|
||||
{
|
||||
key: 'topK', label: 'Top K', type: 'number', group: PARAMETER_GROUP,
|
||||
min: 1, step: 1, stepIncrement: 1,
|
||||
defaultsWhenEmpty: true, placeholder: 'Leave empty for the default',
|
||||
tip: 'Consider only this many candidate tokens at each step.'
|
||||
},
|
||||
{
|
||||
key: 'maxTokens', label: 'Max tokens', type: 'number', group: PARAMETER_GROUP,
|
||||
min: 1, step: 1, stepIncrement: 1,
|
||||
defaultsWhenEmpty: true, placeholder: 'Leave empty for the default',
|
||||
tip: 'Upper bound on the length of the generated answer.'
|
||||
},
|
||||
{
|
||||
key: 'seed', label: 'Seed', type: 'number', group: PARAMETER_GROUP,
|
||||
step: 1, stepIncrement: 1,
|
||||
defaultsWhenEmpty: true, placeholder: 'Leave empty for the default',
|
||||
tip: 'Fixes the randomness, so the same inputs give the same answer. Needed to tell a real change from model noise.'
|
||||
}
|
||||
];
|
||||
|
||||
export type LLMDescriptorSettingsRequest = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue