mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add admin-configurable chat title generation model (#24838)
Adds an admin-configurable deployment-wide setting that controls which
model is used for chat title generation. Admins can pick any enabled
chat model config from the Agents settings page, or leave the setting
unset to keep the existing fast-models-then-chat-model fallback
algorithm.
When a model is selected, both automatic and manual title generation use
only that model, with no silent fallback. When the configured model is
disabled, missing credentials, or otherwise unusable, automatic title
generation skips entirely (best-effort) and manual title regeneration
returns a clear error, so admins notice the misconfiguration instead of
silently routing title traffic through another provider.
## Surface
- New deployment-wide setting stored as a `site_configs` row
(`agents_chat_title_generation_model_override`).
- New experimental endpoint `GET/PUT
/api/experimental/chats/config/model-override/{context}`.
- Frontend: title generation now appears as a third dropdown on the
Agents admin settings page alongside the existing general and explore
context overrides.
## DRY refactors folded in
Title generation is integrated as a third value of the existing
`ChatModelOverrideContext` type alongside `general` and `explore`,
sharing the parameterized HTTP route, SDK methods, generated types, and
frontend API plumbing rather than introducing a parallel surface. The
`Agent` prefix was dropped from the type and route since title
generation is not a delegated agent.
The chatd model-override resolver is also shared.
`resolveConfiguredModelOverride` now takes a `failureMode` parameter:
- Subagent overrides use soft failure: misconfigured overrides are
logged and the parent model is used.
- Title generation uses hard failure: misconfigured overrides return an
explicit error so manual title regeneration surfaces the
misconfiguration and automatic title generation skips instead of
silently falling back.
> Mux is acting on Mike's behalf.
This commit is contained in:
+36
-33
@@ -562,45 +562,48 @@ type UpdateChatPlanModeInstructionsRequest struct {
|
||||
PlanModeInstructions string `json:"plan_mode_instructions"`
|
||||
}
|
||||
|
||||
// ChatAgentModelOverrideContext identifies which chat or subagent context
|
||||
// a deployment override applies to.
|
||||
type ChatAgentModelOverrideContext string
|
||||
// ChatModelOverrideContext identifies which chat model override context a
|
||||
// deployment override applies to.
|
||||
type ChatModelOverrideContext string
|
||||
|
||||
const (
|
||||
ChatAgentModelOverrideContextGeneral ChatAgentModelOverrideContext = "general"
|
||||
ChatAgentModelOverrideContextExplore ChatAgentModelOverrideContext = "explore"
|
||||
ChatModelOverrideContextGeneral ChatModelOverrideContext = "general"
|
||||
ChatModelOverrideContextExplore ChatModelOverrideContext = "explore"
|
||||
ChatModelOverrideContextTitleGeneration ChatModelOverrideContext = "title_generation"
|
||||
)
|
||||
|
||||
// Valid reports whether the override context is one of the supported values.
|
||||
func (c ChatAgentModelOverrideContext) Valid() bool {
|
||||
func (c ChatModelOverrideContext) Valid() bool {
|
||||
switch c {
|
||||
case ChatAgentModelOverrideContextGeneral,
|
||||
ChatAgentModelOverrideContextExplore:
|
||||
case ChatModelOverrideContextGeneral,
|
||||
ChatModelOverrideContextExplore,
|
||||
ChatModelOverrideContextTitleGeneration:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// AllChatAgentModelOverrideContexts returns all supported override contexts.
|
||||
func AllChatAgentModelOverrideContexts() []ChatAgentModelOverrideContext {
|
||||
return []ChatAgentModelOverrideContext{
|
||||
ChatAgentModelOverrideContextGeneral,
|
||||
ChatAgentModelOverrideContextExplore,
|
||||
// AllChatModelOverrideContexts returns all supported override contexts.
|
||||
func AllChatModelOverrideContexts() []ChatModelOverrideContext {
|
||||
return []ChatModelOverrideContext{
|
||||
ChatModelOverrideContextGeneral,
|
||||
ChatModelOverrideContextExplore,
|
||||
ChatModelOverrideContextTitleGeneration,
|
||||
}
|
||||
}
|
||||
|
||||
// ChatAgentModelOverrideResponse is the response body for the chat agent
|
||||
// model override configuration endpoint.
|
||||
type ChatAgentModelOverrideResponse struct {
|
||||
Context ChatAgentModelOverrideContext `json:"context"`
|
||||
ModelConfigID string `json:"model_config_id"`
|
||||
IsMalformed bool `json:"is_malformed"`
|
||||
// ChatModelOverrideResponse is the response body for the chat model override
|
||||
// configuration endpoint.
|
||||
type ChatModelOverrideResponse struct {
|
||||
Context ChatModelOverrideContext `json:"context"`
|
||||
ModelConfigID string `json:"model_config_id"`
|
||||
IsMalformed bool `json:"is_malformed"`
|
||||
}
|
||||
|
||||
// UpdateChatAgentModelOverrideRequest is the request body for updating the
|
||||
// chat agent model override configuration endpoint.
|
||||
type UpdateChatAgentModelOverrideRequest struct {
|
||||
// UpdateChatModelOverrideRequest is the request body for updating the chat
|
||||
// model override configuration endpoint.
|
||||
type UpdateChatModelOverrideRequest struct {
|
||||
ModelConfigID string `json:"model_config_id"`
|
||||
}
|
||||
|
||||
@@ -2098,30 +2101,30 @@ func (c *ExperimentalClient) UpdateChatPlanModeInstructions(ctx context.Context,
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetChatAgentModelOverride returns the deployment-wide chat agent model
|
||||
// override for the requested context.
|
||||
func (c *ExperimentalClient) GetChatAgentModelOverride(ctx context.Context, override ChatAgentModelOverrideContext) (ChatAgentModelOverrideResponse, error) {
|
||||
// GetChatModelOverride returns the deployment-wide chat model override for
|
||||
// the requested context.
|
||||
func (c *ExperimentalClient) GetChatModelOverride(ctx context.Context, override ChatModelOverrideContext) (ChatModelOverrideResponse, error) {
|
||||
path := fmt.Sprintf(
|
||||
"/api/experimental/chats/config/agent-model-override/%s",
|
||||
"/api/experimental/chats/config/model-override/%s",
|
||||
url.PathEscape(string(override)),
|
||||
)
|
||||
res, err := c.Request(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return ChatAgentModelOverrideResponse{}, err
|
||||
return ChatModelOverrideResponse{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return ChatAgentModelOverrideResponse{}, ReadBodyAsError(res)
|
||||
return ChatModelOverrideResponse{}, ReadBodyAsError(res)
|
||||
}
|
||||
var resp ChatAgentModelOverrideResponse
|
||||
var resp ChatModelOverrideResponse
|
||||
return resp, json.NewDecoder(res.Body).Decode(&resp)
|
||||
}
|
||||
|
||||
// UpdateChatAgentModelOverride updates the deployment-wide chat agent model
|
||||
// override for the requested context.
|
||||
func (c *ExperimentalClient) UpdateChatAgentModelOverride(ctx context.Context, override ChatAgentModelOverrideContext, req UpdateChatAgentModelOverrideRequest) error {
|
||||
// UpdateChatModelOverride updates the deployment-wide chat model override for
|
||||
// the requested context.
|
||||
func (c *ExperimentalClient) UpdateChatModelOverride(ctx context.Context, override ChatModelOverrideContext, req UpdateChatModelOverrideRequest) error {
|
||||
path := fmt.Sprintf(
|
||||
"/api/experimental/chats/config/agent-model-override/%s",
|
||||
"/api/experimental/chats/config/model-override/%s",
|
||||
url.PathEscape(string(override)),
|
||||
)
|
||||
res, err := c.Request(ctx, http.MethodPut, path, req)
|
||||
|
||||
Reference in New Issue
Block a user