feat(config): support model-specific max_tokens and fix config key corruption
This commit is contained in:
parent
e011284d8f
commit
60c6bcfe5b
12 changed files with 61 additions and 2 deletions
|
|
@ -131,6 +131,9 @@ func NewAgentInstance(
|
|||
}
|
||||
|
||||
maxTokens := defaults.MaxTokens
|
||||
if mc, err := cfg.GetModelConfig(defaults.OriginalModelName); err == nil {
|
||||
maxTokens = mc.MaxTokens
|
||||
}
|
||||
if maxTokens == 0 {
|
||||
maxTokens = 8192
|
||||
}
|
||||
|
|
|
|||
|
|
@ -327,6 +327,9 @@ type AgentDefaults struct {
|
|||
SubTurn SubTurnConfig `json:"subturn" envPrefix:"PICOCLAW_AGENTS_DEFAULTS_SUBTURN_"`
|
||||
ToolFeedback ToolFeedbackConfig `json:"tool_feedback,omitempty"`
|
||||
SplitOnMarker bool `json:"split_on_marker" env:"PICOCLAW_AGENTS_DEFAULTS_SPLIT_ON_MARKER"` // split messages on <|[SPLIT]|> marker
|
||||
// OriginalModelName holds the original model name as specified in the config.
|
||||
// This is used to resolve the model name in the model_list configuration.
|
||||
OriginalModelName string `json:"-"`
|
||||
}
|
||||
|
||||
const DefaultMaxMediaSize = 20 * 1024 * 1024 // 20 MB
|
||||
|
|
@ -668,6 +671,7 @@ type ModelConfig struct {
|
|||
|
||||
// Optional optimizations
|
||||
RPM int `json:"rpm,omitempty"` // Requests per minute limit
|
||||
MaxTokens int `json:"max_tokens,omitempty"` // Maximum number of tokens per request
|
||||
MaxTokensField string `json:"max_tokens_field,omitempty"` // Field name for max tokens (e.g., "max_completion_tokens")
|
||||
RequestTimeout int `json:"request_timeout,omitempty"`
|
||||
ThinkingLevel string `json:"thinking_level,omitempty"` // Extended thinking: off|low|medium|high|xhigh|adaptive
|
||||
|
|
@ -1287,6 +1291,7 @@ func expandMultiKeyModels(models []*ModelConfig) []*ModelConfig {
|
|||
ConnectMode: m.ConnectMode,
|
||||
Workspace: m.Workspace,
|
||||
RPM: m.RPM,
|
||||
MaxTokens: m.MaxTokens,
|
||||
MaxTokensField: m.MaxTokensField,
|
||||
RequestTimeout: m.RequestTimeout,
|
||||
ThinkingLevel: m.ThinkingLevel,
|
||||
|
|
@ -1307,6 +1312,7 @@ func expandMultiKeyModels(models []*ModelConfig) []*ModelConfig {
|
|||
ConnectMode: m.ConnectMode,
|
||||
Workspace: m.Workspace,
|
||||
RPM: m.RPM,
|
||||
MaxTokens: m.MaxTokens,
|
||||
MaxTokensField: m.MaxTokensField,
|
||||
RequestTimeout: m.RequestTimeout,
|
||||
ThinkingLevel: m.ThinkingLevel,
|
||||
|
|
|
|||
|
|
@ -660,6 +660,7 @@ type modelConfigV0 struct {
|
|||
|
||||
// Optional optimizations
|
||||
RPM int `json:"rpm,omitempty"` // Requests per minute limit
|
||||
MaxTokens int `json:"max_tokens,omitempty"` // Maximum number of tokens per request
|
||||
MaxTokensField string `json:"max_tokens_field,omitempty"` // Field name for max tokens (e.g., "max_completion_tokens")
|
||||
RequestTimeout int `json:"request_timeout,omitempty"`
|
||||
ThinkingLevel string `json:"thinking_level,omitempty"` // Extended thinking: off|low|medium|high|xhigh|adaptive
|
||||
|
|
@ -744,6 +745,7 @@ func (c *configV0) Migrate() (*Config, error) {
|
|||
ConnectMode: m.ConnectMode,
|
||||
Workspace: m.Workspace,
|
||||
RPM: m.RPM,
|
||||
MaxTokens: m.MaxTokens,
|
||||
MaxTokensField: m.MaxTokensField,
|
||||
RequestTimeout: m.RequestTimeout,
|
||||
ThinkingLevel: m.ThinkingLevel,
|
||||
|
|
|
|||
|
|
@ -499,6 +499,7 @@ func loadConfigV0(data []byte) (migratable, error) {
|
|||
ConnectMode: m.ConnectMode,
|
||||
Workspace: m.Workspace,
|
||||
RPM: m.RPM,
|
||||
MaxTokens: m.MaxTokens,
|
||||
MaxTokensField: m.MaxTokensField,
|
||||
RequestTimeout: m.RequestTimeout,
|
||||
ThinkingLevel: m.ThinkingLevel,
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ func TestExpandMultiKeyModels_PreservesOtherFields(t *testing.T) {
|
|||
APIBase: "https://api.example.com",
|
||||
Proxy: "http://proxy:8080",
|
||||
RPM: 60,
|
||||
MaxTokens: 1024,
|
||||
MaxTokensField: "max_completion_tokens",
|
||||
RequestTimeout: 30,
|
||||
ThinkingLevel: "high",
|
||||
|
|
@ -212,6 +213,9 @@ func TestExpandMultiKeyModels_PreservesOtherFields(t *testing.T) {
|
|||
if primary.RPM != 60 {
|
||||
t.Errorf("expected rpm preserved, got %d", primary.RPM)
|
||||
}
|
||||
if primary.MaxTokens != 1024 {
|
||||
t.Errorf("expected max_tokens preserved, got %d", primary.MaxTokens)
|
||||
}
|
||||
if primary.MaxTokensField != "max_completion_tokens" {
|
||||
t.Errorf("expected max_tokens_field preserved, got %q", primary.MaxTokensField)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,6 +113,9 @@ func Run(debug bool, homePath, configPath string, allowEmptyStartup bool) error
|
|||
}
|
||||
|
||||
if modelID != "" {
|
||||
if cfg.Agents.Defaults.OriginalModelName == "" {
|
||||
cfg.Agents.Defaults.OriginalModelName = cfg.Agents.Defaults.ModelName
|
||||
}
|
||||
cfg.Agents.Defaults.ModelName = modelID
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ type modelResponse struct {
|
|||
ConnectMode string `json:"connect_mode,omitempty"`
|
||||
Workspace string `json:"workspace,omitempty"`
|
||||
RPM int `json:"rpm,omitempty"`
|
||||
MaxTokens int `json:"max_tokens,omitempty"`
|
||||
MaxTokensField string `json:"max_tokens_field,omitempty"`
|
||||
RequestTimeout int `json:"request_timeout,omitempty"`
|
||||
ThinkingLevel string `json:"thinking_level,omitempty"`
|
||||
|
|
@ -81,6 +82,7 @@ func (h *Handler) handleListModels(w http.ResponseWriter, r *http.Request) {
|
|||
ConnectMode: m.ConnectMode,
|
||||
Workspace: m.Workspace,
|
||||
RPM: m.RPM,
|
||||
MaxTokens: m.MaxTokens,
|
||||
MaxTokensField: m.MaxTokensField,
|
||||
RequestTimeout: m.RequestTimeout,
|
||||
ThinkingLevel: m.ThinkingLevel,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export interface ModelInfo {
|
|||
connect_mode?: string
|
||||
workspace?: string
|
||||
rpm?: number
|
||||
max_tokens?: number
|
||||
max_tokens_field?: string
|
||||
request_timeout?: number
|
||||
thinking_level?: string
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ interface AddForm {
|
|||
connectMode: string
|
||||
workspace: string
|
||||
rpm: string
|
||||
maxTokens: string
|
||||
maxTokensField: string
|
||||
requestTimeout: string
|
||||
thinkingLevel: string
|
||||
|
|
@ -48,6 +49,7 @@ const EMPTY_ADD_FORM: AddForm = {
|
|||
connectMode: "",
|
||||
workspace: "",
|
||||
rpm: "",
|
||||
maxTokens: "",
|
||||
maxTokensField: "",
|
||||
requestTimeout: "",
|
||||
thinkingLevel: "",
|
||||
|
|
@ -128,6 +130,7 @@ export function AddModelSheet({
|
|||
connect_mode: form.connectMode.trim() || undefined,
|
||||
workspace: form.workspace.trim() || undefined,
|
||||
rpm: form.rpm ? Number(form.rpm) : undefined,
|
||||
max_tokens: form.maxTokens ? Number(form.maxTokens) : undefined,
|
||||
max_tokens_field: form.maxTokensField.trim() || undefined,
|
||||
request_timeout: form.requestTimeout
|
||||
? Number(form.requestTimeout)
|
||||
|
|
@ -302,6 +305,19 @@ export function AddModelSheet({
|
|||
/>
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
label={t("models.field.maxTokens")}
|
||||
hint={t("models.field.maxTokensHint")}
|
||||
>
|
||||
<Input
|
||||
value={form.maxTokens}
|
||||
onChange={setField("maxTokens")}
|
||||
placeholder="0"
|
||||
type="number"
|
||||
min={0}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
label={t("models.field.maxTokensField")}
|
||||
hint={t("models.field.maxTokensFieldHint")}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ interface EditForm {
|
|||
connectMode: string
|
||||
workspace: string
|
||||
rpm: string
|
||||
maxTokens: string
|
||||
maxTokensField: string
|
||||
requestTimeout: string
|
||||
thinkingLevel: string
|
||||
|
|
@ -58,6 +59,7 @@ export function EditModelSheet({
|
|||
connectMode: "",
|
||||
workspace: "",
|
||||
rpm: "",
|
||||
maxTokens: "",
|
||||
maxTokensField: "",
|
||||
requestTimeout: "",
|
||||
thinkingLevel: "",
|
||||
|
|
@ -77,6 +79,7 @@ export function EditModelSheet({
|
|||
connectMode: model.connect_mode ?? "",
|
||||
workspace: model.workspace ?? "",
|
||||
rpm: model.rpm ? String(model.rpm) : "",
|
||||
maxTokens: model.max_tokens ? String(model.max_tokens) : "",
|
||||
maxTokensField: model.max_tokens_field ?? "",
|
||||
requestTimeout: model.request_timeout
|
||||
? String(model.request_timeout)
|
||||
|
|
@ -111,6 +114,7 @@ export function EditModelSheet({
|
|||
connect_mode: form.connectMode || undefined,
|
||||
workspace: form.workspace || undefined,
|
||||
rpm: form.rpm ? Number(form.rpm) : undefined,
|
||||
max_tokens: form.maxTokens ? Number(form.maxTokens) : undefined,
|
||||
max_tokens_field: form.maxTokensField || undefined,
|
||||
request_timeout: form.requestTimeout
|
||||
? Number(form.requestTimeout)
|
||||
|
|
@ -273,6 +277,19 @@ export function EditModelSheet({
|
|||
/>
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
label={t("models.field.maxTokens")}
|
||||
hint={t("models.field.maxTokensHint")}
|
||||
>
|
||||
<Input
|
||||
value={form.maxTokens}
|
||||
onChange={setField("maxTokens")}
|
||||
placeholder="0"
|
||||
type="number"
|
||||
min={0}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
label={t("models.field.maxTokensField")}
|
||||
hint={t("models.field.maxTokensFieldHint")}
|
||||
|
|
|
|||
|
|
@ -208,6 +208,8 @@
|
|||
"rpmHint": "Maximum requests per minute. 0 = no limit.",
|
||||
"thinkingLevel": "Thinking Level",
|
||||
"thinkingLevelHint": "Extended thinking budget: off, low, medium, high, xhigh, adaptive.",
|
||||
"maxTokens": "Max Tokens",
|
||||
"maxTokensHint": "Maximum tokens allowed for a single request. 0 = use default configuration.",
|
||||
"maxTokensField": "Max Tokens Field",
|
||||
"maxTokensFieldHint": "Override the request field name for max tokens, e.g. max_completion_tokens.",
|
||||
"extraBody": "Extra Body",
|
||||
|
|
@ -531,4 +533,4 @@
|
|||
"empty": "Waiting for logs..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -208,6 +208,8 @@
|
|||
"rpmHint": "每分钟最大请求数,0 表示不限制。",
|
||||
"thinkingLevel": "思考级别",
|
||||
"thinkingLevelHint": "扩展思考预算:off、low、medium、high、xhigh、adaptive。",
|
||||
"maxTokens": "最大 Token 数",
|
||||
"maxTokensHint": "单次请求允许生成的最大 Token 数。若设置为 0,则使用默认配置。",
|
||||
"maxTokensField": "Max Tokens 字段名",
|
||||
"maxTokensFieldHint": "覆盖请求中 max_tokens 的字段名,例如 max_completion_tokens。",
|
||||
"extraBody": "Extra Body",
|
||||
|
|
@ -531,4 +533,4 @@
|
|||
"empty": "等待日志中..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue