diff --git a/cfg/dev.yaml b/cfg/dev.yaml index 08e9452be..7859196d8 100644 --- a/cfg/dev.yaml +++ b/cfg/dev.yaml @@ -89,6 +89,7 @@ probod: api-key: "thisisnotasecret" temperature: 0.1 model-name: "gpt-4o" + max-tokens: 4096 custom-domains: renewal-interval: 3600 diff --git a/contrib/helm/README.md b/contrib/helm/README.md index b64717dae..5416b5f98 100644 --- a/contrib/helm/README.md +++ b/contrib/helm/README.md @@ -413,6 +413,7 @@ spec: | probo.openai.apiKey | string | `""` | OpenAI API key for AI features (optional) | | probo.openai.temperature | float | `0.1` | OpenAI temperature setting | | probo.openai.modelName | string | `"gpt-4o"` | OpenAI model name | +| probo.openai.maxTokens | int | `4096` | Maximum output tokens for LLM requests | | probo.customDomains.enabled | bool | `false` | Enable custom domains feature | | probo.customDomains.renewalInterval | int | `3600` | Certificate renewal interval in seconds | | probo.customDomains.provisionInterval | int | `30` | Domain provision interval in seconds | diff --git a/contrib/helm/charts/probo/templates/deployment.yaml b/contrib/helm/charts/probo/templates/deployment.yaml index 778395f41..3e86bf420 100644 --- a/contrib/helm/charts/probo/templates/deployment.yaml +++ b/contrib/helm/charts/probo/templates/deployment.yaml @@ -217,6 +217,8 @@ spec: value: {{ .Values.probo.openai.temperature | quote }} - name: OPENAI_MODEL_NAME value: {{ .Values.probo.openai.modelName | quote }} + - name: OPENAI_MAX_TOKENS + value: {{ .Values.probo.openai.maxTokens | quote }} {{- end }} # Custom Domains {{- if .Values.probo.customDomains.enabled }} diff --git a/contrib/helm/charts/probo/values-production.yaml.example b/contrib/helm/charts/probo/values-production.yaml.example index 194957847..2b81caa0f 100644 --- a/contrib/helm/charts/probo/values-production.yaml.example +++ b/contrib/helm/charts/probo/values-production.yaml.example @@ -157,6 +157,7 @@ probo: apiKey: "CHANGE_ME_OPENAI_API_KEY" temperature: 0.1 modelName: "gpt-4o" + maxTokens: 4096 # OpenTelemetry tracing (optional) tracing: diff --git a/contrib/helm/charts/probo/values.yaml b/contrib/helm/charts/probo/values.yaml index 9c5ddc9a3..6a28ea618 100644 --- a/contrib/helm/charts/probo/values.yaml +++ b/contrib/helm/charts/probo/values.yaml @@ -252,6 +252,7 @@ probo: apiKey: "" temperature: 0.1 modelName: "gpt-4o" + maxTokens: 4096 # Custom domains configuration (optional) customDomains: diff --git a/e2e/console/testdata/config.yaml b/e2e/console/testdata/config.yaml index f3b6daeea..44df37f38 100644 --- a/e2e/console/testdata/config.yaml +++ b/e2e/console/testdata/config.yaml @@ -65,6 +65,7 @@ probod: api-key: "thisisnotasecret" temperature: 0.1 model-name: "gpt-4o" + max-tokens: 4096 custom-domains: renewal-interval: 3600 diff --git a/pkg/agents/agents.go b/pkg/agents/agents.go index ff5af3f21..2ee97dde2 100644 --- a/pkg/agents/agents.go +++ b/pkg/agents/agents.go @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Probo Inc . +// Copyright (c) 2025-2026 Probo Inc . // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -20,12 +20,13 @@ import ( ) type Agent struct { - l *log.Logger - client *llm.Client - model string - temp float64 + l *log.Logger + client *llm.Client + model string + temp float64 + maxTokens int } -func NewAgent(l *log.Logger, client *llm.Client, model string, temp float64) *Agent { - return &Agent{l: l, client: client, model: model, temp: temp} +func NewAgent(l *log.Logger, client *llm.Client, model string, temp float64, maxTokens int) *Agent { + return &Agent{l: l, client: client, model: model, temp: temp, maxTokens: maxTokens} } diff --git a/pkg/agents/changelog_generator.go b/pkg/agents/changelog_generator.go index d2a79cb01..d7a1e6694 100644 --- a/pkg/agents/changelog_generator.go +++ b/pkg/agents/changelog_generator.go @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Probo Inc . +// Copyright (c) 2025-2026 Probo Inc . // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -55,6 +55,7 @@ func (a *Agent) GenerateChangelog(ctx context.Context, oldContent string, newCon agent.WithInstructions(changelogGeneratorSystemPrompt), agent.WithModel(a.model), agent.WithTemperature(a.temp), + agent.WithMaxTokens(a.maxTokens), ) result, err := ag.Run( diff --git a/pkg/agents/vendor_assessment.go b/pkg/agents/vendor_assessment.go index 922fd4fcf..c1085e929 100644 --- a/pkg/agents/vendor_assessment.go +++ b/pkg/agents/vendor_assessment.go @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Probo Inc . +// Copyright (c) 2025-2026 Probo Inc . // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -128,6 +128,7 @@ func (a *Agent) AssessVendor(ctx context.Context, websiteURL string) (*vendorInf agent.WithInstructions(assessVendorSystemPrompt), agent.WithModel(a.model), agent.WithTemperature(a.temp), + agent.WithMaxTokens(a.maxTokens), ) typedResult, err := agent.RunTyped[vendorInfo]( diff --git a/pkg/bootstrap/builder.go b/pkg/bootstrap/builder.go index 8659e2153..3d462c02c 100644 --- a/pkg/bootstrap/builder.go +++ b/pkg/bootstrap/builder.go @@ -151,6 +151,7 @@ func (b *Builder) Build() (*probod.FullConfig, error) { APIKey: b.getEnv("OPENAI_API_KEY"), Temperature: b.getEnvFloatOrDefault("OPENAI_TEMPERATURE", 0.1), ModelName: b.getEnvOrDefault("OPENAI_MODEL_NAME", "gpt-4o"), + MaxTokens: b.getEnvIntOrDefault("OPENAI_MAX_TOKENS", 4096), }, CustomDomains: probod.CustomDomainsConfig{ RenewalInterval: b.getEnvIntOrDefault("CUSTOM_DOMAINS_RENEWAL_INTERVAL", 3600), diff --git a/pkg/bootstrap/builder_test.go b/pkg/bootstrap/builder_test.go index ee1f9914e..60d2418ca 100644 --- a/pkg/bootstrap/builder_test.go +++ b/pkg/bootstrap/builder_test.go @@ -164,6 +164,7 @@ func TestBuilder_Build_Defaults(t *testing.T) { // OpenAI config assert.Equal(t, 0.1, cfg.Probod.OpenAI.Temperature) assert.Equal(t, "gpt-4o", cfg.Probod.OpenAI.ModelName) + assert.Equal(t, 4096, cfg.Probod.OpenAI.MaxTokens) // Custom domains config assert.Equal(t, 3600, cfg.Probod.CustomDomains.RenewalInterval) @@ -234,6 +235,7 @@ func TestBuilder_Build_CustomValues(t *testing.T) { env["OPENAI_API_KEY"] = "sk-test-key" env["OPENAI_TEMPERATURE"] = "0.5" env["OPENAI_MODEL_NAME"] = "gpt-4-turbo" + env["OPENAI_MAX_TOKENS"] = "8192" // Custom domains env["CUSTOM_DOMAINS_RESOLVER_ADDR"] = "1.1.1.1:53" env["ACME_ACCOUNT_KEY"] = "-----BEGIN EC PRIVATE KEY-----\ntest\n-----END EC PRIVATE KEY-----" @@ -297,6 +299,7 @@ func TestBuilder_Build_CustomValues(t *testing.T) { assert.Equal(t, "sk-test-key", cfg.Probod.OpenAI.APIKey) assert.Equal(t, 0.5, cfg.Probod.OpenAI.Temperature) assert.Equal(t, "gpt-4-turbo", cfg.Probod.OpenAI.ModelName) + assert.Equal(t, 8192, cfg.Probod.OpenAI.MaxTokens) // Custom domains assert.Equal(t, "1.1.1.1:53", cfg.Probod.CustomDomains.ResolverAddr) assert.Equal(t, "-----BEGIN EC PRIVATE KEY-----\ntest\n-----END EC PRIVATE KEY-----", cfg.Probod.CustomDomains.ACME.AccountKey) diff --git a/pkg/probo/service.go b/pkg/probo/service.go index 03087c0ef..b536fe352 100644 --- a/pkg/probo/service.go +++ b/pkg/probo/service.go @@ -59,6 +59,7 @@ type ( llmClient *llm.Client llmModel string llmTemperature float64 + llmMaxTokens int html2pdfConverter *html2pdf.Converter acmeService *certmanager.ACMEService fileManager *filemanager.Service @@ -132,6 +133,7 @@ func NewService( llmClient *llm.Client, llmModel string, llmTemperature float64, + llmMaxTokens int, html2pdfConverter *html2pdf.Converter, acmeService *certmanager.ACMEService, fileManagerService *filemanager.Service, @@ -157,6 +159,7 @@ func NewService( llmClient: llmClient, llmModel: llmModel, llmTemperature: llmTemperature, + llmMaxTokens: llmMaxTokens, html2pdfConverter: html2pdfConverter, acmeService: acmeService, fileManager: fileManagerService, @@ -178,7 +181,7 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { baseURL: s.baseURL, scope: coredata.NewScope(tenantID), tokenSecret: s.tokenSecret, - agent: agents.NewAgent(nil, s.llmClient, s.llmModel, s.llmTemperature), + agent: agents.NewAgent(nil, s.llmClient, s.llmModel, s.llmTemperature, s.llmMaxTokens), fileManager: s.fileManager, esign: s.esign, } diff --git a/pkg/probod/openai_config.go b/pkg/probod/openai_config.go index af6e6bf90..91a5a315c 100644 --- a/pkg/probod/openai_config.go +++ b/pkg/probod/openai_config.go @@ -19,6 +19,7 @@ type LLMConfig struct { APIKey string `json:"api-key"` // for OpenAI and Anthropic ModelName string `json:"model-name"` Temperature float64 `json:"temperature"` + MaxTokens int `json:"max-tokens"` } type OpenAIConfig = LLMConfig diff --git a/pkg/probod/probod.go b/pkg/probod/probod.go index f1fb66465..162d581e5 100644 --- a/pkg/probod/probod.go +++ b/pkg/probod/probod.go @@ -445,6 +445,7 @@ func (impl *Implm) Run( llmClient, impl.cfg.OpenAI.ModelName, impl.cfg.OpenAI.Temperature, + impl.cfg.OpenAI.MaxTokens, html2pdfConverter, acmeService, fileManagerService,