Add reasoning effort
This commit is contained in:
@@ -157,11 +157,12 @@ func (j *Job) Run(ctx context.Context) Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res, err := j.llm.Completions(
|
res, err := j.llm.Completions(
|
||||||
ctx,
|
ctx, llm.CompletionsParams{
|
||||||
j.model,
|
Model: j.model,
|
||||||
j.SystemMessage(),
|
SystemMessage: j.SystemMessage(),
|
||||||
j.MaxIterations(),
|
MaxIterations: j.MaxIterations(),
|
||||||
messages,
|
Messages: messages,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
duration := time.Since(start)
|
duration := time.Since(start)
|
||||||
|
|||||||
@@ -25,6 +25,15 @@ type CompletionsResult struct {
|
|||||||
Timings *Timings
|
Timings *Timings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CompletionsParams holds parameters for Completions and CompletionsStream.
|
||||||
|
type CompletionsParams struct {
|
||||||
|
Model string
|
||||||
|
SystemMessage string
|
||||||
|
MaxIterations int
|
||||||
|
Messages []Message
|
||||||
|
ThinkingBudgetTokens *int
|
||||||
|
}
|
||||||
|
|
||||||
// Completions sends messages to the LLM using the specified model.
|
// Completions sends messages to the LLM using the specified model.
|
||||||
// If systemMessage is non-empty, it overrides the configured system message.
|
// If systemMessage is non-empty, it overrides the configured system message.
|
||||||
// maxIterations caps the number of agent loop iterations.
|
// maxIterations caps the number of agent loop iterations.
|
||||||
@@ -32,15 +41,14 @@ type CompletionsResult struct {
|
|||||||
// Returns all messages generated during the completions request, including
|
// Returns all messages generated during the completions request, including
|
||||||
// tool calls and tool results, along with usage and timings from the final response.
|
// tool calls and tool results, along with usage and timings from the final response.
|
||||||
func (c *Client) Completions(
|
func (c *Client) Completions(
|
||||||
ctx context.Context,
|
ctx context.Context, p CompletionsParams,
|
||||||
model string,
|
|
||||||
systemMessage string,
|
|
||||||
maxIterations int,
|
|
||||||
messages []Message,
|
|
||||||
) (*CompletionsResult, error) {
|
) (*CompletionsResult, error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
model, systemMessage, maxIterations, messages, thinkingBudgetTokens :=
|
||||||
|
p.Model, p.SystemMessage, p.MaxIterations, p.Messages, p.ThinkingBudgetTokens
|
||||||
|
|
||||||
// Use request system message if provided, config default otherwise.
|
// Use request system message if provided, config default otherwise.
|
||||||
smsg := c.systemMessage
|
smsg := c.systemMessage
|
||||||
if systemMessage != "" {
|
if systemMessage != "" {
|
||||||
@@ -68,7 +76,7 @@ func (c *Client) Completions(
|
|||||||
var finalUsage *Usage
|
var finalUsage *Usage
|
||||||
var finalTimings *Timings
|
var finalTimings *Timings
|
||||||
for i := 0; maxIterations == 0 || i < maxIterations; i++ {
|
for i := 0; maxIterations == 0 || i < maxIterations; i++ {
|
||||||
cr, err := c.completions(ctx, model, messages)
|
cr, err := c.completions(ctx, model, thinkingBudgetTokens, messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("completions: %w", err)
|
return nil, fmt.Errorf("completions: %w", err)
|
||||||
}
|
}
|
||||||
@@ -106,12 +114,18 @@ func (c *Client) Completions(
|
|||||||
// completions sends a single non-streaming request and returns the
|
// completions sends a single non-streaming request and returns the
|
||||||
// full API response.
|
// full API response.
|
||||||
func (c *Client) completions(
|
func (c *Client) completions(
|
||||||
ctx context.Context, model string, messages []Message,
|
ctx context.Context, model string, thinkingBudgetTokens *int, messages []Message,
|
||||||
) (*ChatResponse, error) {
|
) (*ChatResponse, error) {
|
||||||
|
kwargs := map[string]any{}
|
||||||
|
if thinkingBudgetTokens != nil {
|
||||||
|
kwargs["enable_thinking"] = *thinkingBudgetTokens != 0
|
||||||
|
}
|
||||||
body, err := json.Marshal(ChatRequest{
|
body, err := json.Marshal(ChatRequest{
|
||||||
Model: model,
|
Model: model,
|
||||||
Messages: messages,
|
Messages: messages,
|
||||||
Tools: c.tools,
|
Tools: c.tools,
|
||||||
|
ThinkingBudgetTokens: thinkingBudgetTokens,
|
||||||
|
ChatTemplateKWARGS: kwargs,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
@@ -232,17 +246,15 @@ const (
|
|||||||
// means unlimited (no cap).
|
// means unlimited (no cap).
|
||||||
// Returns ErrMaxIterations if the iteration limit is exceeded.
|
// Returns ErrMaxIterations if the iteration limit is exceeded.
|
||||||
func (c *Client) CompletionsStream(
|
func (c *Client) CompletionsStream(
|
||||||
ctx context.Context,
|
ctx context.Context, p CompletionsParams, events chan<- StreamEvent,
|
||||||
model string,
|
|
||||||
systemMessage string,
|
|
||||||
maxIterations int,
|
|
||||||
messages []Message,
|
|
||||||
events chan<- StreamEvent,
|
|
||||||
) error {
|
) error {
|
||||||
defer close(events)
|
defer close(events)
|
||||||
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
model, systemMessage, maxIterations, messages, thinkingBudgetTokens :=
|
||||||
|
p.Model, p.SystemMessage, p.MaxIterations, p.Messages, p.ThinkingBudgetTokens
|
||||||
|
|
||||||
// Use request system message if provided, config default otherwise.
|
// Use request system message if provided, config default otherwise.
|
||||||
smsg := c.systemMessage
|
smsg := c.systemMessage
|
||||||
if systemMessage != "" {
|
if systemMessage != "" {
|
||||||
@@ -265,7 +277,7 @@ func (c *Client) CompletionsStream(
|
|||||||
|
|
||||||
// Loop for tool calls. maxIterations == 0 means unlimited.
|
// Loop for tool calls. maxIterations == 0 means unlimited.
|
||||||
for i := 0; maxIterations == 0 || i < maxIterations; i++ {
|
for i := 0; maxIterations == 0 || i < maxIterations; i++ {
|
||||||
choices, err := c.completionsStream(ctx, messages, model, events)
|
choices, err := c.completionsStream(ctx, messages, model, thinkingBudgetTokens, events)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("completions stream: %w", err)
|
return fmt.Errorf("completions stream: %w", err)
|
||||||
}
|
}
|
||||||
@@ -304,12 +316,18 @@ type streamAccum struct {
|
|||||||
// response, and returns all assistant messages from the response choices.
|
// response, and returns all assistant messages from the response choices.
|
||||||
// Sends each message to the events channel. Usage and timings are included
|
// Sends each message to the events channel. Usage and timings are included
|
||||||
// on the done event for the last message.
|
// on the done event for the last message.
|
||||||
func (c *Client) completionsStream(ctx context.Context, messages []Message, model string, events chan<- StreamEvent) ([]Message, error) {
|
func (c *Client) completionsStream(ctx context.Context, messages []Message, model string, thinkingBudgetTokens *int, events chan<- StreamEvent) ([]Message, error) {
|
||||||
|
kwargs := map[string]any{}
|
||||||
|
if thinkingBudgetTokens != nil {
|
||||||
|
kwargs["enable_thinking"] = *thinkingBudgetTokens != 0
|
||||||
|
}
|
||||||
body, err := json.Marshal(ChatRequest{
|
body, err := json.Marshal(ChatRequest{
|
||||||
Model: model,
|
Model: model,
|
||||||
Messages: messages,
|
Messages: messages,
|
||||||
Stream: true,
|
Stream: true,
|
||||||
Tools: c.tools,
|
Tools: c.tools,
|
||||||
|
ThinkingBudgetTokens: thinkingBudgetTokens,
|
||||||
|
ChatTemplateKWARGS: kwargs,
|
||||||
StreamOptions: &StreamOptions{IncludeUsage: true},
|
StreamOptions: &StreamOptions{IncludeUsage: true},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -35,18 +35,18 @@ func TestCompletionsStreamStreamsReasoningDeltas(t *testing.T) {
|
|||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
errCh <- client.CompletionsStream(
|
errCh <- client.CompletionsStream(
|
||||||
context.Background(),
|
context.Background(), CompletionsParams{
|
||||||
"test-model",
|
Model: "test-model",
|
||||||
"",
|
SystemMessage: "",
|
||||||
0,
|
MaxIterations: 0,
|
||||||
[]Message{{
|
Messages: []Message{{
|
||||||
Role: RoleUser,
|
Role: RoleUser,
|
||||||
ContentParts: []ContentPart{{
|
ContentParts: []ContentPart{{
|
||||||
Type: ContentTypeText,
|
Type: ContentTypeText,
|
||||||
Text: "hello",
|
Text: "hello",
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
events,
|
}, events,
|
||||||
)
|
)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -131,17 +131,18 @@ func TestCompletionsReturnsUsageAndTimings(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res, err := client.Completions(
|
res, err := client.Completions(
|
||||||
context.Background(),
|
context.Background(), CompletionsParams{
|
||||||
"test-model",
|
Model: "test-model",
|
||||||
"",
|
SystemMessage: "",
|
||||||
0,
|
MaxIterations: 0,
|
||||||
[]Message{{
|
Messages: []Message{{
|
||||||
Role: RoleUser,
|
Role: RoleUser,
|
||||||
ContentParts: []ContentPart{{
|
ContentParts: []ContentPart{{
|
||||||
Type: ContentTypeText,
|
Type: ContentTypeText,
|
||||||
Text: "hi",
|
Text: "hi",
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Completions: %v", err)
|
t.Fatalf("Completions: %v", err)
|
||||||
@@ -205,18 +206,18 @@ func TestCompletionsStreamEmitsUsageEvent(t *testing.T) {
|
|||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
errCh <- client.CompletionsStream(
|
errCh <- client.CompletionsStream(
|
||||||
context.Background(),
|
context.Background(), CompletionsParams{
|
||||||
"test-model",
|
Model: "test-model",
|
||||||
"",
|
SystemMessage: "",
|
||||||
0,
|
MaxIterations: 0,
|
||||||
[]Message{{
|
Messages: []Message{{
|
||||||
Role: RoleUser,
|
Role: RoleUser,
|
||||||
ContentParts: []ContentPart{{
|
ContentParts: []ContentPart{{
|
||||||
Type: ContentTypeText,
|
Type: ContentTypeText,
|
||||||
Text: "hi",
|
Text: "hi",
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
events,
|
}, events,
|
||||||
)
|
)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ type ChatRequest struct {
|
|||||||
ToolChoice any `json:"tool_choice,omitempty"`
|
ToolChoice any `json:"tool_choice,omitempty"`
|
||||||
StreamOptions *StreamOptions `json:"stream_options,omitempty"`
|
StreamOptions *StreamOptions `json:"stream_options,omitempty"`
|
||||||
ParallelToolCalls *bool `json:"parallel_tool_calls,omitempty"`
|
ParallelToolCalls *bool `json:"parallel_tool_calls,omitempty"`
|
||||||
ReasoningEffort string `json:"reasoning_effort,omitempty"`
|
ChatTemplateKWARGS map[string]any `json:"chat_template_kwargs,omitempty"`
|
||||||
|
ThinkingBudgetTokens *int `json:"thinking_budget_tokens,omitempty"`
|
||||||
ServiceTier string `json:"service_tier,omitempty"`
|
ServiceTier string `json:"service_tier,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,17 +77,18 @@ func TestIntegration_Completions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res, err := client.Completions(
|
res, err := client.Completions(
|
||||||
context.Background(),
|
context.Background(), CompletionsParams{
|
||||||
testModel(t),
|
Model: testModel(t),
|
||||||
"",
|
SystemMessage: "",
|
||||||
0,
|
MaxIterations: 0,
|
||||||
[]Message{{
|
Messages: []Message{{
|
||||||
Role: RoleUser,
|
Role: RoleUser,
|
||||||
ContentParts: []ContentPart{{
|
ContentParts: []ContentPart{{
|
||||||
Type: "text",
|
Type: "text",
|
||||||
Text: "Say hello in three words.",
|
Text: "Say hello in three words.",
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Completions: %v", err)
|
t.Fatalf("Completions: %v", err)
|
||||||
@@ -117,18 +118,18 @@ func TestIntegration_CompletionsStream(t *testing.T) {
|
|||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
errCh <- client.CompletionsStream(
|
errCh <- client.CompletionsStream(
|
||||||
context.Background(),
|
context.Background(), CompletionsParams{
|
||||||
testModel(t),
|
Model: testModel(t),
|
||||||
"",
|
SystemMessage: "",
|
||||||
0,
|
MaxIterations: 0,
|
||||||
[]Message{{
|
Messages: []Message{{
|
||||||
Role: RoleUser,
|
Role: RoleUser,
|
||||||
ContentParts: []ContentPart{{
|
ContentParts: []ContentPart{{
|
||||||
Type: "text",
|
Type: "text",
|
||||||
Text: "Say hello in three words.",
|
Text: "Say hello in three words.",
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
events,
|
}, events,
|
||||||
)
|
)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -182,17 +183,18 @@ func TestIntegration_ToolCalling(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res, err := client.Completions(
|
res, err := client.Completions(
|
||||||
context.Background(),
|
context.Background(), CompletionsParams{
|
||||||
testModel(t),
|
Model: testModel(t),
|
||||||
"",
|
SystemMessage: "",
|
||||||
10,
|
MaxIterations: 10,
|
||||||
[]Message{{
|
Messages: []Message{{
|
||||||
Role: RoleUser,
|
Role: RoleUser,
|
||||||
ContentParts: []ContentPart{{
|
ContentParts: []ContentPart{{
|
||||||
Type: "text",
|
Type: "text",
|
||||||
Text: "Use the echo tool to say 'hello'",
|
Text: "Use the echo tool to say 'hello'",
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Completions: %v", err)
|
t.Fatalf("Completions: %v", err)
|
||||||
|
|||||||
@@ -450,6 +450,8 @@ type Request struct {
|
|||||||
SystemMessage string `json:"system_message,omitempty"`
|
SystemMessage string `json:"system_message,omitempty"`
|
||||||
// MaxIterations caps the number of agent loop turns (0 = unlimited).
|
// MaxIterations caps the number of agent loop turns (0 = unlimited).
|
||||||
MaxIterations int `json:"max_iterations,omitempty"`
|
MaxIterations int `json:"max_iterations,omitempty"`
|
||||||
|
// ThinkingBudgetTokens is the llama.cpp reasoning budget (-1 = unlimited, 0 = off).
|
||||||
|
ThinkingBudgetTokens *int `json:"thinking_budget_tokens,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response is the response format for chat and voice endpoints.
|
// Response is the response format for chat and voice endpoints.
|
||||||
@@ -545,7 +547,13 @@ func (svc *Service) chat(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res, err := llmc.Completions(
|
res, err := llmc.Completions(
|
||||||
ctx, model, req.SystemMessage, req.MaxIterations, req.Messages,
|
ctx, llm.CompletionsParams{
|
||||||
|
Model: model,
|
||||||
|
SystemMessage: req.SystemMessage,
|
||||||
|
MaxIterations: req.MaxIterations,
|
||||||
|
Messages: req.Messages,
|
||||||
|
ThinkingBudgetTokens: req.ThinkingBudgetTokens,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ErrorContext(
|
log.ErrorContext(
|
||||||
@@ -717,7 +725,13 @@ func (svc *Service) chatStream(w http.ResponseWriter, r *http.Request) {
|
|||||||
)
|
)
|
||||||
go func() {
|
go func() {
|
||||||
errs <- llmc.CompletionsStream(
|
errs <- llmc.CompletionsStream(
|
||||||
ctx, model, req.SystemMessage, req.MaxIterations, req.Messages, events,
|
ctx, llm.CompletionsParams{
|
||||||
|
Model: model,
|
||||||
|
SystemMessage: req.SystemMessage,
|
||||||
|
MaxIterations: req.MaxIterations,
|
||||||
|
Messages: req.Messages,
|
||||||
|
ThinkingBudgetTokens: req.ThinkingBudgetTokens,
|
||||||
|
}, events,
|
||||||
)
|
)
|
||||||
close(errs)
|
close(errs)
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -730,7 +730,7 @@ body {
|
|||||||
|
|
||||||
.settings-label__sub {
|
.settings-label__sub {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: var(--s-2);
|
font-size: var(--s-1);
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: var(--color-text-muted);
|
color: var(--color-text-muted);
|
||||||
margin-top: 0.125rem;
|
margin-top: 0.125rem;
|
||||||
@@ -756,10 +756,6 @@ body {
|
|||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-field {
|
|
||||||
margin-bottom: var(--s1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-textarea {
|
.settings-textarea {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { WakeLock } from './wakelock.js';
|
|||||||
const STREAM_ENDPOINT = '/v1/chat/voice/stream';
|
const STREAM_ENDPOINT = '/v1/chat/voice/stream';
|
||||||
const SYSTEM_MESSAGE_KEY = 'odidere_system_message';
|
const SYSTEM_MESSAGE_KEY = 'odidere_system_message';
|
||||||
const MAX_TURNS_KEY = 'odidere_max_turns';
|
const MAX_TURNS_KEY = 'odidere_max_turns';
|
||||||
|
const REASONING_BUDGET_KEY = 'odidere_reasoning_budget';
|
||||||
const MUTE_KEY = 'odidere_mute';
|
const MUTE_KEY = 'odidere_mute';
|
||||||
const ICONS_URL = '/static/icons.svg';
|
const ICONS_URL = '/static/icons.svg';
|
||||||
|
|
||||||
@@ -111,6 +112,9 @@ class Odidere {
|
|||||||
'compose-settings-close',
|
'compose-settings-close',
|
||||||
);
|
);
|
||||||
this.$maxTurnsInput = document.getElementById('max-turns-input');
|
this.$maxTurnsInput = document.getElementById('max-turns-input');
|
||||||
|
this.$reasoningBudgetInput = document.getElementById(
|
||||||
|
'reasoning-budget-input',
|
||||||
|
);
|
||||||
this.$compose = document.querySelector('.compose');
|
this.$compose = document.querySelector('.compose');
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
@@ -268,9 +272,6 @@ class Odidere {
|
|||||||
if (e.target === this.$composeSettingsOverlay)
|
if (e.target === this.$composeSettingsOverlay)
|
||||||
this._closeComposeSettings();
|
this._closeComposeSettings();
|
||||||
});
|
});
|
||||||
this.$maxTurnsInput.addEventListener('input', () => {
|
|
||||||
this._setMaxTurns(this.$maxTurnsInput.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
// --- Model/voice change persistence ---
|
// --- Model/voice change persistence ---
|
||||||
this.settings.$model.addEventListener('change', () =>
|
this.settings.$model.addEventListener('change', () =>
|
||||||
@@ -640,6 +641,11 @@ class Odidere {
|
|||||||
payload.max_iterations = maxTurns;
|
payload.max_iterations = maxTurns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const reasoningBudget = this._getReasoningBudget();
|
||||||
|
if (reasoningBudget !== null) {
|
||||||
|
payload.thinking_budget_tokens = reasoningBudget;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear attachments and location after building payload.
|
// Clear attachments and location after building payload.
|
||||||
this.clearAttachments();
|
this.clearAttachments();
|
||||||
this.clearLocation();
|
this.clearLocation();
|
||||||
@@ -1170,11 +1176,14 @@ class Odidere {
|
|||||||
|
|
||||||
_openComposeSettings() {
|
_openComposeSettings() {
|
||||||
this.$maxTurnsInput.value = this._getMaxTurns();
|
this.$maxTurnsInput.value = this._getMaxTurns();
|
||||||
|
this.$reasoningBudgetInput.value = this._getReasoningBudget() ?? -1;
|
||||||
this.$composeSettingsOverlay.classList.add('open');
|
this.$composeSettingsOverlay.classList.add('open');
|
||||||
this.$composeSettingsClose.focus();
|
this.$composeSettingsClose.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
_closeComposeSettings() {
|
_closeComposeSettings() {
|
||||||
|
this._setMaxTurns(this.$maxTurnsInput.value);
|
||||||
|
this._setReasoningBudget(this.$reasoningBudgetInput.value);
|
||||||
this.$composeSettingsOverlay.classList.remove('open');
|
this.$composeSettingsOverlay.classList.remove('open');
|
||||||
this.$composeSettings.focus();
|
this.$composeSettings.focus();
|
||||||
}
|
}
|
||||||
@@ -1188,6 +1197,16 @@ class Odidere {
|
|||||||
localStorage.setItem(MAX_TURNS_KEY, String(value));
|
localStorage.setItem(MAX_TURNS_KEY, String(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getReasoningBudget() {
|
||||||
|
const stored = localStorage.getItem(REASONING_BUDGET_KEY);
|
||||||
|
if (stored === null) return null;
|
||||||
|
return Number(stored);
|
||||||
|
}
|
||||||
|
|
||||||
|
_setReasoningBudget(value) {
|
||||||
|
localStorage.setItem(REASONING_BUDGET_KEY, String(value));
|
||||||
|
}
|
||||||
|
|
||||||
// ====================
|
// ====================
|
||||||
// TWO-PRESS SAFETY PATTERNS
|
// TWO-PRESS SAFETY PATTERNS
|
||||||
// ====================
|
// ====================
|
||||||
|
|||||||
@@ -29,6 +29,24 @@
|
|||||||
aria-label="Max iterations"
|
aria-label="Max iterations"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-field">
|
||||||
|
<label class="settings-label" for="reasoning-budget-input">
|
||||||
|
Reasoning Budget
|
||||||
|
<span class="settings-label__sub">
|
||||||
|
Only supported by some models and inference engines.
|
||||||
|
<br>
|
||||||
|
-1 = unlimited, 0 = off · 512 ≈ low · 2048 ≈ med · 8192 ≈ high
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="settings-select"
|
||||||
|
id="reasoning-budget-input"
|
||||||
|
value="-1"
|
||||||
|
aria-label="Reasoning budget"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|||||||
Reference in New Issue
Block a user