add reasoning effort setting for providers

Add a reasoning effort field to the completion provider config, sent as-is to the model. Reasoning models such as GPT-5.x need it set to "none" to use tools. Also switch to max_completion_tokens.
This commit is contained in:
Abhinav Raut
2026-07-12 04:48:01 +05:30
parent 1343790353
commit ef0add0fff
5 changed files with 39 additions and 12 deletions
@@ -79,6 +79,17 @@
</FormItem>
</FormField>
<FormField v-slot="{ componentField }" name="reasoning_effort">
<FormItem>
<FormLabel>{{ t('admin.ai.reasoningEffort') }}</FormLabel>
<FormControl>
<Input type="text" placeholder="none" v-bind="componentField" />
</FormControl>
<FormDescription>{{ t('admin.ai.reasoningEffortHint') }}</FormDescription>
<FormMessage />
</FormItem>
</FormField>
<FormField v-slot="{ componentField }" name="instructions">
<FormItem class="md:col-span-2">
<FormLabel>{{ t('admin.ai.instructions') }}</FormLabel>
@@ -264,6 +275,7 @@ const form = useForm({
base_url: z.string().optional(),
api_key: z.string().optional(),
instructions: z.string().optional(),
reasoning_effort: z.string().optional(),
temperature: numberField().refine((v) => isBlank(v) || inRange(v, 0, 2), {
message: t('admin.ai.temperatureRange')
}),
@@ -281,6 +293,7 @@ const form = useForm({
base_url: '',
api_key: '',
instructions: '',
reasoning_effort: '',
temperature: fieldDefaults.temperature,
max_tokens: fieldDefaults.maxTokens,
dimensions: fieldDefaults.dimensions,
@@ -298,6 +311,7 @@ onMounted(async () => {
base_url: data.base_url || '',
api_key: data.api_key || '',
instructions: data.instructions || '',
reasoning_effort: data.reasoning_effort || '',
// Fall back to sensible defaults when the provider has nothing saved (0/absent).
temperature: data.temperature != null ? String(data.temperature) : fieldDefaults.temperature,
max_tokens: data.max_tokens ? String(data.max_tokens) : fieldDefaults.maxTokens,
@@ -321,6 +335,7 @@ const onSubmit = form.handleSubmit(async (values) => {
if (props.showCompletionFields) {
payload.instructions = values.instructions || ''
payload.vision = !!values.vision
payload.reasoning_effort = (values.reasoning_effort || '').trim()
if (values.temperature !== '' && values.temperature != null)
payload.temperature = Number(values.temperature)
if (values.max_tokens !== '' && values.max_tokens != null)
+2
View File
@@ -130,6 +130,8 @@
"admin.ai.temperatureRange": "Temperature must be a number between 0 and 2.",
"admin.ai.positiveNumber": "Enter a whole number greater than 0.",
"admin.ai.maxTokens": "Max tokens",
"admin.ai.reasoningEffort": "Reasoning effort",
"admin.ai.reasoningEffortHint": "Leave blank for most models. Reasoning models such as GPT-5.x require 'none' to use tools; other values are 'low', 'medium' or 'high'.",
"admin.ai.instructions": "Custom instructions",
"admin.ai.instructionsHint": "Added to every Copilot and reply-draft prompt. Use it to set tone and format, e.g. keep replies under 3 sentences, match the brand voice, always reply in the customer's language.",
"admin.ai.vision": "Model supports image input",
+10 -9
View File
@@ -218,15 +218,16 @@ func (m *Manager) UpdateProviderConfig(providerType string, in models.ProviderCo
}
cfg := models.ProviderConfig{
Provider: "openai",
BaseURL: in.BaseURL,
APIKey: apiKey,
Model: in.Model,
Temperature: in.Temperature,
MaxTokens: in.MaxTokens,
Dimensions: in.Dimensions,
Instructions: in.Instructions,
Vision: in.Vision,
Provider: "openai",
BaseURL: in.BaseURL,
APIKey: apiKey,
Model: in.Model,
Temperature: in.Temperature,
MaxTokens: in.MaxTokens,
Dimensions: in.Dimensions,
Instructions: in.Instructions,
Vision: in.Vision,
ReasoningEffort: in.ReasoningEffort,
}
b, err := json.Marshal(cfg)
if err != nil {
+3
View File
@@ -45,6 +45,9 @@ type ProviderConfig struct {
MaxTokens int `json:"max_tokens"`
Dimensions int `json:"dimensions"`
Instructions string `json:"instructions"`
// ReasoningEffort, when set, is sent as-is. Reasoning models (e.g. GPT-5.x) need "none" to use
// tools on /chat/completions; leave blank for models that reject the param.
ReasoningEffort string `json:"reasoning_effort,omitempty"`
// Vision marks the completion model as accepting image input; when false the harness drops image parts.
Vision bool `json:"vision"`
}
+9 -3
View File
@@ -84,13 +84,19 @@ func (o *OpenAIClient) SendChatCompletion(payload models.ChatCompletionPayload)
o.lo.Debug("chat completion request", "model", model, "messages", len(messages), "images", sentImages, "vision", o.cfg.Vision, "tools", len(payload.Tools))
body := map[string]any{
"model": model,
"messages": messages,
"max_tokens": maxTokens,
"model": model,
"messages": messages,
"max_completion_tokens": maxTokens,
}
// Only send optional params the admin set. Reasoning models (e.g. GPT-5.x) reject a non-default
// temperature and require reasoning_effort "none" to use tools on /chat/completions; leave
// temperature blank and set reasoning_effort accordingly for those.
if o.cfg.Temperature != nil {
body["temperature"] = *o.cfg.Temperature
}
if o.cfg.ReasoningEffort != "" {
body["reasoning_effort"] = o.cfg.ReasoningEffort
}
if len(payload.Tools) > 0 {
body["tools"] = payload.Tools
body["tool_choice"] = "auto"