diff --git a/chat.go b/chat.go index dbdff11..88339ef 100644 --- a/chat.go +++ b/chat.go @@ -42,6 +42,7 @@ type Request struct { Prompt string `json:"prompt"` Model string `json:"model"` Temperature float64 `json:"temperature"` + Iterations int64 `json:"iterations"` JSON bool `json:"json"` Search bool `json:"search"` Reasoning Reasoning `json:"reasoning"` @@ -92,6 +93,10 @@ func (r *Request) Parse() (*openrouter.ChatCompletionRequest, error) { request.Model = r.Model + if r.Iterations < 1 || r.Iterations > 50 { + return nil, fmt.Errorf("invalid iterations (1-50): %d", r.Iterations) + } + if r.Temperature < 0 || r.Temperature > 2 { return nil, fmt.Errorf("invalid temperature (0-2): %f", r.Temperature) } @@ -253,10 +258,10 @@ func HandleChat(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - for iteration := range env.Settings.MaxIterations { - debug("iteration %d of %d", iteration+1, env.Settings.MaxIterations) + for iteration := range raw.Iterations { + debug("iteration %d of %d", iteration+1, raw.Iterations) - if iteration == env.Settings.MaxIterations-1 { + if iteration == raw.Iterations-1 { debug("no more tool calls") request.Tools = nil diff --git a/env.go b/env.go index f02c5b3..c0cf1da 100644 --- a/env.go +++ b/env.go @@ -18,8 +18,7 @@ type EnvTokens struct { } type EnvSettings struct { - CleanContent bool `json:"cleanup"` - MaxIterations uint `json:"iterations"` + CleanContent bool `json:"cleanup"` } type EnvUser struct { @@ -44,8 +43,7 @@ type Environment struct { var env = Environment{ // defaults Settings: EnvSettings{ - CleanContent: true, - MaxIterations: 3, + CleanContent: true, }, } @@ -67,9 +65,6 @@ func (e *Environment) Init() error { log.Warning("Debug mode enabled") } - // check max iterations - e.Settings.MaxIterations = max(e.Settings.MaxIterations, 1) - // check if server secret is set if e.Tokens.Secret == "" { log.Warning("Missing tokens.secret, generating new...") @@ -125,8 +120,7 @@ func (e *Environment) Store() error { "$.tokens.openrouter": {yaml.HeadComment(" openrouter.ai api token (required)")}, "$.tokens.exa": {yaml.HeadComment(" exa search api token (optional; used by search tools)")}, - "$.settings.cleanup": {yaml.HeadComment(" normalize unicode in assistant output (optional; default: true)")}, - "$.settings.iterations": {yaml.HeadComment(" max model turns per request (optional; default: 3)")}, + "$.settings.cleanup": {yaml.HeadComment(" normalize unicode in assistant output (optional; default: true)")}, "$.authentication.enabled": {yaml.HeadComment(" require login with username and password")}, "$.authentication.users": {yaml.HeadComment(" list of users with bcrypt password hashes")}, diff --git a/example.config.yml b/example.config.yml index 9287c5e..aac5508 100644 --- a/example.config.yml +++ b/example.config.yml @@ -12,8 +12,6 @@ tokens: settings: # normalize unicode in assistant output (optional; default: true) cleanup: true - # max model turns per request (optional; default: 3) - iterations: 3 authentication: # require login with username and password diff --git a/main.go b/main.go index 2804d23..2947d1b 100644 --- a/main.go +++ b/main.go @@ -64,8 +64,10 @@ func cache(next http.Handler) http.Handler { path := strings.ToLower(r.URL.Path) ext := filepath.Ext(path) - if ext == ".svg" || ext == ".ttf" || strings.HasSuffix(path, ".min.js") || strings.HasSuffix(path, ".min.css") { + if ext == ".png" || ext == ".svg" || ext == ".ttf" || strings.HasSuffix(path, ".min.js") || strings.HasSuffix(path, ".min.css") { w.Header().Set("Cache-Control", "public, max-age=3024000, immutable") + } else if env.Debug { + w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") } next.ServeHTTP(w, r) diff --git a/static/css/chat.css b/static/css/chat.css index 5c053bc..557c462 100644 --- a/static/css/chat.css +++ b/static/css/chat.css @@ -532,7 +532,7 @@ body:not(.loading) #loading { } .statistics .ttft::before { - background-image: url(icons/ttft.svg); + background-image: url(icons/time.svg); } .statistics .tps::before { @@ -789,13 +789,18 @@ input.invalid { } #reasoning-tokens, -#temperature { +#temperature, +#iterations { appearance: textfield; width: 48px; padding: 2px 4px; text-align: right; } +#iterations { + width: 30px; +} + label[for="role"] { background-image: url(icons/user.svg); } @@ -812,6 +817,10 @@ label[for="temperature"] { background-image: url(icons/temperature.svg); } +label[for="iterations"] { + background-image: url(icons/time.svg); +} + label[for="reasoning-effort"] { background-image: url(icons/reasoning.svg); } diff --git a/static/css/icons/ttft.svg b/static/css/icons/time.svg similarity index 100% rename from static/css/icons/ttft.svg rename to static/css/icons/time.svg diff --git a/static/index.html b/static/index.html index d113756..57f7d91 100644 --- a/static/index.html +++ b/static/index.html @@ -58,6 +58,10 @@ +